From ccf9c3906cd8df8774834972e866953cfa7ea00f Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 07:30:50 -0600 Subject: [PATCH 01/43] Fix: preserve viewer drafts across file navigation --- .../change.md | 4 + .../deltas/ThreeMDViewer.md | 2 +- .../plan.md | 4 + .../requirements.md | 2 +- .../tasks.md | 4 + .../testing.md | 4 + docs/evidence/viewer-navigation/README.md | 11 + docs/evidence/viewer-navigation/desktop.jpg | Bin 0 -> 121196 bytes .../viewer-navigation/phone-files.jpg | Bin 0 -> 29171 bytes docs/evidence/viewer-navigation/phone.jpg | Bin 0 -> 45676 bytes hi/tools.md | 2 +- specs/ThreeMDViewer/ThreeMDViewer.spec.md | 6 +- specs/ThreeMDViewer/context.md | 4 + specs/ThreeMDViewer/requirements.md | 4 +- specs/ThreeMDViewer/tasks.md | 4 + specs/ThreeMDViewer/testing.md | 4 + uitests/viewer.spec.mjs | 191 ++++++++++ web/viewer.html | 360 +++++++++++++----- 18 files changed, 505 insertions(+), 101 deletions(-) create mode 100644 docs/evidence/viewer-navigation/README.md create mode 100644 docs/evidence/viewer-navigation/desktop.jpg create mode 100644 docs/evidence/viewer-navigation/phone-files.jpg create mode 100644 docs/evidence/viewer-navigation/phone.jpg diff --git a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/change.md b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/change.md index 919c8c9..03bfbfb 100644 --- a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/change.md +++ b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/change.md @@ -30,3 +30,7 @@ Leif requested continued UI and UX implementation on 2026-10-09. This artifact r ## No-spec Rationale Not applicable + +## File navigation fix after PR 92 + +Leif merged PR 92 and requested a new fix PR. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. Session drafts do not write local or GitHub files and are cleared by refreshing or opening another collection. Existing definition approval remains unrecorded. diff --git a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/deltas/ThreeMDViewer.md b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/deltas/ThreeMDViewer.md index be7876d..5aa8eaf 100644 --- a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/deltas/ThreeMDViewer.md +++ b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/deltas/ThreeMDViewer.md @@ -4,7 +4,7 @@ ### REQUIREMENT REQ-ThreeMDViewer-003 -The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. +The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. Acceptance Criteria: diff --git a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/plan.md b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/plan.md index ab10bcd..b5453f0 100644 --- a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/plan.md +++ b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/plan.md @@ -31,3 +31,7 @@ The cube parity follow-up uses the live Sculpt view as reference: 0.5 lit glyph ## Continuing UI and UX pass Compact the identity row and toolbar. Use a native Document disclosure for export and conversion tools, keep composition entry selection in the stage, and show insertion tools only in Edit. Place camera controls below the canvas and use the canvas dimensions for camera framing. Add keyboard camera, tab, and slice navigation, with one tab stop in each navigation group. Explain nongrid documents and unavailable GPU support with a Preview action. Add busy/recovery feedback around the existing GitHub loader. + +## File navigation fix + +Keep a page-owned draft for each opened file and composition entry, including invalid or empty edits. Share linked entry drafts with their corresponding source file. Refresh the line index from drafts when searching, use draft text when packing, and preserve selection and caret when returning. Validate a local open before replacing the collection. Show filenames and edited state across views, add a file filter with an explicit empty result, and reveal opened documents on narrow screens. Replace stale source queries on explicit navigation. diff --git a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/requirements.md b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/requirements.md index f5c685f..3b3c74d 100644 --- a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/requirements.md +++ b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/requirements.md @@ -5,7 +5,7 @@ artifact: requirements # Requirements -- **REQ-ThreeMDViewer-003** The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. +- **REQ-ThreeMDViewer-003** The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. - **REQ-ThreeMDViewer-004** The viewer page SHALL NOT offer a render-mode switch and SHALL NOT autoplay. Preview SHALL stay on one plane. Cubes SHALL draw complete, nearly cell-sized cubes with WebGL2, lit glyph-colored fill at 0.5 opacity and visible glyph-colored edges. The selected Z slice SHALL have gold edges at 0.8 opacity while retaining its glyph fill. The background SHALL be rgb(0.065, 0.085, 0.10). X SHALL be the column, Y the text row with row 0 toward the top, and Z the plane index. Orbit, zoom, and slice selection SHALL reuse the installed geometry. Each redraw SHALL use one instanced draw. Fit SHALL restore yaw 0.6, pitch 0.35, and zoom 1 without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The element bundle SHALL stay a text renderer. REQ-ThreeMDViewer-001 and REQ-ThreeMDViewer-002 stay. GitHub open, search, sections, pack, kind 2, hostname checks, and the text-only element stay. diff --git a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/tasks.md b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/tasks.md index b03f8c4..68e5329 100644 --- a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/tasks.md +++ b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/tasks.md @@ -27,3 +27,7 @@ artifact: tasks Pinned Trust runs after the feature head is committed and pushed; its result is recorded in the PR and local verification output. Definition and human diff approval remain open. + +- [x] Preserve file, linked-entry, invalid, and empty drafts with caret and selected plane across navigation. +- [x] Mark edits, filter files, navigate by keyboard, reveal phone documents, and avoid stale source queries. +- [x] Search and pack current drafts, and preserve the collection after a failed open. diff --git a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/testing.md b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/testing.md index 3d015c5..71ad608 100644 --- a/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/testing.md +++ b/.specsync/changes/put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below/testing.md @@ -23,3 +23,7 @@ Final parity browser verification: 70 passed on Chromium and WebKit. Strict Thre ## Continuing UI and UX pass The Chromium/WebKit suite covers camera controls, phone layout and non-overlapping controls, Document disclosure dismissal, text and kind 2 download fidelity, editor focus after the save shortcut, prose Preview and sample loading, 30-slice keyboard navigation, GitHub rate-limit recovery, and WebGL2-unavailable guidance. Inspect dark/light desktop, Edit, and phone views and preserve screenshots under docs/evidence/viewer-ui/. + +## File navigation fix + +The Chromium and WebKit viewer suite covers exact draft restoration, invalid and empty edits, the caret and slice, composition-entry independence, linked entry/file sharing, original-text edited markers, current-text download, search and pack, file filtering and keyboard selection, mobile document reveal, failed-open preservation, and stale source-query removal on navigation. Screenshots from live desktop and phone inspection are in `docs/evidence/viewer-navigation/`. These are agent checks and do not record human definition approval. diff --git a/docs/evidence/viewer-navigation/README.md b/docs/evidence/viewer-navigation/README.md new file mode 100644 index 0000000..eec5bbd --- /dev/null +++ b/docs/evidence/viewer-navigation/README.md @@ -0,0 +1,11 @@ +# Viewer file navigation verification + +Agent inspection on 2026-10-10, after PR 92 merged. The local viewer served this fix branch at `http://127.0.0.1:8234/viewer.html`. + +- `desktop.jpg`: opened a folder containing the public Character orb and the viewer starter, edited the starter title and glyphs, switched to the orb and back, and inspected the preserved draft in Cubes. The filename, Edited marker, file indicator, and selected walls slice are visible. +- `phone.jpg`: the same edited document at 390 by 844. The title, source filename, Edited marker, camera controls, and plane outline leave room for the cube stage. +- `phone-files.jpg`: filtered the opened files on the phone. The matching file keeps its path and edited indicator. Choosing it reveals the document and focuses its current view. The temporary viewport was reset after inspection. + +These are live browser screenshots and agent visual checks. They are not human review or SpecSync definition approval. Drafts are held only in memory for the current collection; refreshing or opening another collection clears them. Download exports the selected document and does not overwrite a local or GitHub source file. Composition profiles are not rewritten when an entry is edited. + +The viewer regression suite covers file and composition draft restoration, linked file/entry sharing, invalid and empty drafts, caret and slice restoration, edited markers, current-text download, search and packing, filtered keyboard file selection, phone document reveal, failed-open preservation, and current-document reload URLs. Existing cube, context, export, editor, and accessibility checks also remain in the suite. See the PR for the exact commit's test and Trust results. diff --git a/docs/evidence/viewer-navigation/desktop.jpg b/docs/evidence/viewer-navigation/desktop.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5573f461f43918c58adb3f8d0484c8d696db3078 GIT binary patch literal 121196 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%0DUwTH_ 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

-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 element stays a text renderer. Decode, composition, linked fold 6. Apple LZFSE is refused. The element stays a text renderer. The library stays free of filesystem and network I/O. 7. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. Fit SHALL restore yaw 0.6, pitch 0.35, and zoom 1 without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The Document disclosure closes after an action, outside click, or Escape; Escape returns focus to its summary. The source download shortcut keeps focus in Edit. GitHub open exposes a busy state, prevents duplicate submits, and recovers its controls even on failure. Zoom is bounded from 0.45 to 3.2. Camera controls use the canvas dimensions for framing and occupy a separate strip below it. +8. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. Drafts are in memory for the current collection. Download exports the current document and does not write the original file or clear its Edited marker. Opening another collection or refreshing clears these session drafts. Linked entries share their draft with the matching source file. Composition downloads remain exports of the selected document; edits do not rewrite the composition profile. + The cube input keeps at most 12 distinct non-space characters, at most 64 columns and 64 rows per plane, and at most 4000 occupied cells. Space, dot, and tab are empty. Cube painting and erasing into source, 256 cubed volumes, sparse worlds, OBJ export, and changes to Sculpt are outside this pass. The page does not rebuild the element or open-document bundles. ## Behavioral Examples @@ -142,3 +144,5 @@ The cube input keeps at most 12 distinct non-space characters, at most 64 column | 2026-10-10 | ThreeMDViewer change | Draw every cube face. Each cell is a solid cube. | | 2026-10-09 | agent:codex | Match Sculpt fill, glyph edges, gold selected-slice edges, background, document axes, and camera framing; retain one instanced draw and geometry reuse. | | 2026-10-09 | agent:codex | Compact the workspace, group document actions, add Fit and accessible camera/slice controls, and clarify empty and loading states under Leif’s request to continue improving UI and UX. The layout definition remains an unapproved draft. | + +| 2026-10-10 | agent:codex | Preserve file and composition drafts across navigation, expose edited state, and improve file filtering, keyboard navigation, mobile reveal, and current-document URLs in a follow-up PR after PR 92 merged. The definition remains an unapproved draft. | diff --git a/specs/ThreeMDViewer/context.md b/specs/ThreeMDViewer/context.md index 6056b5e..f92eb01 100644 --- a/specs/ThreeMDViewer/context.md +++ b/specs/ThreeMDViewer/context.md @@ -40,3 +40,7 @@ spec: ThreeMDViewer.spec.md - Leif directly requested continued UI and UX work on 2026-10-09. This covers the compact workspace and controls in the existing page scope; it does not record definition approval, human diff review, or a merge. - The canvas occupies the space above the camera strip. Framing and picking use its actual client dimensions; changing view or viewport still does not resize an established WebGL bitmap. - Export and conversion actions use a native disclosure with natural button focus, Escape dismissal, and outside-click closure. The source download shortcut preserves editor focus. + +- PR 92 has merged. Leif requested a new fix PR for file navigation. Draft state belongs to the page and survives file and composition-entry switches within the current collection. It is not browser storage or a write to the source files. The existing definition remains unapproved. + +- File activation focuses the document before restoring its caret. Chromium clears a restored selection when the editor remains blurred; focus-first restoration passes in both engines. Packing uses the current draft of the active document for each opened file, without rewriting composition profiles. The line index is reused until a draft or the collection changes. diff --git a/specs/ThreeMDViewer/requirements.md b/specs/ThreeMDViewer/requirements.md index 9350b19..03b1051 100644 --- a/specs/ThreeMDViewer/requirements.md +++ b/specs/ThreeMDViewer/requirements.md @@ -12,7 +12,7 @@ spec: ThreeMDViewer.spec.md - **REQ-ThreeMDViewer-001** The viewer page SHALL present files, source, and the live plane view. It SHALL open a public GitHub repo, folder, or file, or a file or folder from this computer. Search SHALL read every opened line and open that plane. Markdown headings SHALL become planes. Opened files SHALL pack into one text document, and that document SHALL download as uncompressed kind 2. The `` element SHALL stay a text renderer. - **REQ-ThreeMDViewer-002** The page SHALL accept a GitHub locator only when the host is `github.com`, `www.github.com`, or `raw.githubusercontent.com`, or when the input is an `owner/repo` name. It SHALL NOT treat those names as a match when they appear only as a substring. A public load SHALL skip `node_modules`, SHALL keep at most 400 files, and SHALL skip a file larger than 1.5 MB. The line index SHALL keep at most 12,000 rows. Apple LZFSE SHALL be refused. The ThreeMD library SHALL stay free of filesystem and network I/O. -- **REQ-ThreeMDViewer-003** The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. +- **REQ-ThreeMDViewer-003** The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. - **REQ-ThreeMDViewer-004** The viewer page SHALL NOT offer a render-mode switch and SHALL NOT autoplay. Preview SHALL stay on one plane. Cubes SHALL draw complete, nearly cell-sized cubes with WebGL2, lit glyph-colored fill at 0.5 opacity and visible glyph-colored edges. The selected Z slice SHALL have gold edges at 0.8 opacity while retaining its glyph fill. The background SHALL be rgb(0.065, 0.085, 0.10). X SHALL be the column, Y the text row with row 0 toward the top, and Z the plane index. Orbit, zoom, and slice selection SHALL reuse the installed geometry. Each redraw SHALL use one instanced draw. Fit SHALL restore yaw 0.6, pitch 0.35, and zoom 1 without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The element bundle SHALL stay a text renderer. ## Constraints @@ -48,7 +48,7 @@ Acceptance Criteria: ### REQ-ThreeMDViewer-003 -The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. +The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. Acceptance Criteria: diff --git a/specs/ThreeMDViewer/tasks.md b/specs/ThreeMDViewer/tasks.md index 53352d4..1b91728 100644 --- a/specs/ThreeMDViewer/tasks.md +++ b/specs/ThreeMDViewer/tasks.md @@ -35,3 +35,7 @@ spec: ThreeMDViewer.spec.md - **QA**: agent:codex local browser and visual verification; human review pending - **Design**: n/a - **Dev**: pending + +- [x] Preserve file, linked-entry, invalid, and empty drafts with caret and selected plane across navigation. +- [x] Mark edits, filter files, navigate by keyboard, reveal phone documents, and avoid stale source queries. +- [x] Search and pack current drafts, and preserve the collection after a failed open. diff --git a/specs/ThreeMDViewer/testing.md b/specs/ThreeMDViewer/testing.md index feeb1cb..c07a758 100644 --- a/specs/ThreeMDViewer/testing.md +++ b/specs/ThreeMDViewer/testing.md @@ -41,3 +41,7 @@ spec: ThreeMDViewer.spec.md - The viewer suite exercises the new controls in Chromium and WebKit. Binary export is compared as parsed document fields and plane bodies because decoding returns canonical text. Camera direction assertions are independent of font-driven aspect-ratio changes. - Live desktop dark, desktop light, Edit, and phone views are inspected and captured in `docs/evidence/viewer-ui/`. These are agent visual checks, not human approval. + +## File navigation fix + +The Chromium and WebKit viewer suite covers exact draft restoration, invalid and empty edits, the caret and slice, composition-entry independence, linked entry/file sharing, original-text edited markers, current-text download, search and pack, file filtering and keyboard selection, mobile document reveal, failed-open preservation, and stale source-query removal on navigation. Screenshots from live desktop and phone inspection are in `docs/evidence/viewer-navigation/`. These are agent checks and do not record human definition approval. diff --git a/uitests/viewer.spec.mjs b/uitests/viewer.spec.mjs index cd71a2f..aee53ca 100644 --- a/uitests/viewer.spec.mjs +++ b/uitests/viewer.spec.mjs @@ -1,4 +1,22 @@ import { test, expect } from "@playwright/test"; +import { mkdtemp, mkdir, writeFile, rm, readFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +const draftDocument = (title, body = "Original marker") => `---\n3md: 1.0\naxis: layer\ntitle: ${title}\n---\n@plane z=0 label="First"\n${body}\n@plane z=1 label="Second"\nSecond marker\n`; +async function openCollection(page, files) { + const directory = await mkdtemp(join(tmpdir(), "3md-viewer-drafts-")); + try { + for (const [path, text] of Object.entries(files)) { + const target = join(directory, path); + await mkdir(join(target, ".."), { recursive: true }); + await writeFile(target, text); + } + await page.locator("#folderInput").setInputFiles(directory); + await expect(page.locator("#fileList button")).toHaveCount(Object.keys(files).length); + } finally { await rm(directory, { recursive: true, force: true }); } +} +const openedFile = (page, name) => page.locator("#fileList button").filter({ has: page.locator(".file-name", { hasText: name }) }); // The official viewer/editor (web/viewer.html): live-edit any 3md and see it // render in the component, with shareable links. @@ -909,4 +927,177 @@ test.describe("viewer & editor (viewer.html)", () => { expect(await page.evaluate(() => document.getElementById("lab").document.title)).toBe("Small sculpture"); }); + test("file switches preserve edited, invalid, and empty drafts with caret and slice", async ({ page }) => { + await page.goto("/viewer.html"); + await viewerReady(page); + await openCollection(page, { "a.3md": draftDocument("A"), "nested/b.3md": draftDocument("B") }); + await openedFile(page, "a.3md").click(); + await showEditor(page); + const original = await page.locator("#editor").inputValue(); + const changed = draftDocument("A edited", "Unique draft text"); + await page.fill("#editor", changed); + await page.evaluate(() => { + document.getElementById("editor").setSelectionRange(20, 25); + document.getElementById("lab").goTo(1); + }); + await openedFile(page, "b.3md").click(); + await openedFile(page, "a.3md").click(); + await expect(page.locator("#editor")).toHaveValue(changed); + expect(await page.evaluate(() => { + const ed = document.getElementById("editor"); + return { start: ed.selectionStart, end: ed.selectionEnd, plane: document.getElementById("lab").currentIndex }; + })).toEqual({ start: 20, end: 25, plane: 1 }); + await expect(page.locator("#draftState")).toBeVisible(); + await expect(openedFile(page, "a.3md")).toHaveAttribute("data-edited", "true"); + await page.click("#documentMenu summary"); + const downloadEvent = page.waitForEvent("download"); + await page.click("#dlBtn"); + const download = await downloadEvent; + expect(await readFile(await download.path(), "utf8")).toBe(changed); + await expect(page.locator("#draftState")).toBeVisible(); + for (const draft of ["invalid draft kept verbatim", ""]) { + await page.fill("#editor", draft); + await openedFile(page, "b.3md").click(); + await openedFile(page, "a.3md").click(); + await expect(page.locator("#editor")).toHaveValue(draft); + } + await page.fill("#editor", original); + await expect(page.locator("#draftState")).toBeHidden(); + await expect(openedFile(page, "a.3md")).toHaveAttribute("data-edited", "false"); + }); + + test("composition entry switches preserve each draft without copying it into another entry", async ({ page }) => { + await page.goto("/viewer.html"); + await viewerReady(page); + await page.waitForFunction(() => window.threeMdCatalogCount > 200); + await page.fill("#findExample", "Extensions/shared-grove.3md"); + await page.locator("#findList button", { hasText: "layer · Extensions/shared-grove.3md" }).click(); + await showEditor(page); + const rootId = await page.locator("#piece").inputValue(); + const rootSource = await page.locator("#editor").inputValue(); + const changedRoot = rootSource + "\nRoot draft marker\n"; + await page.fill("#editor", changedRoot); + await page.locator("#piece").focus(); + await page.selectOption("#piece", "canopy"); + await expect(page.locator("#piece")).toBeFocused(); + const canopySource = await page.locator("#editor").inputValue(); + expect(canopySource).not.toContain("Root draft marker"); + const changedCanopy = canopySource + "\nCanopy draft marker\n"; + await page.fill("#editor", changedCanopy); + await page.selectOption("#piece", rootId); + await expect(page.locator("#editor")).toHaveValue(changedRoot); + await page.selectOption("#piece", "canopy"); + await expect(page.locator("#editor")).toHaveValue(changedCanopy); + await page.click("#cubesTab"); + await expect(page.locator("#draftState")).toBeVisible(); + await expect(page.locator("#sourceName")).toBeVisible(); + }); + + test("linked entries and file navigation share the same draft", async ({ page }) => { + await page.goto("/viewer.html"); + await viewerReady(page); + const files = {}; + for (const path of ["scene.3md", "models/house.3md", "models/tree.3md", "models/tower.3md"]) { + files[path] = await readFile(new URL(`../Examples/LinkedVillage/${path}`, import.meta.url), "utf8"); + } + await openCollection(page, files); + await showEditor(page); + const rootId = await page.locator("#piece").inputValue(); + const houseId = await page.locator("#piece option").evaluateAll((options) => options.find((option) => option.textContent.endsWith("models/house.3md")).value); + await page.selectOption("#piece", houseId); + const changed = (await page.locator("#editor").inputValue()) + "\nLinked house draft\n"; + await page.fill("#editor", changed); + await openedFile(page, "house.3md").click(); + await expect(page.locator("#editor")).toHaveValue(changed); + const revised = changed + "From the file list\n"; + await page.fill("#editor", revised); + await openedFile(page, "scene.3md").click(); + await page.selectOption("#piece", rootId); + await page.selectOption("#piece", houseId); + await expect(page.locator("#editor")).toHaveValue(revised); + await expect(openedFile(page, "house.3md")).toHaveAttribute("data-edited", "true"); + }); + + test("search and packing use drafts rather than original file text", async ({ page }) => { + await page.goto("/viewer.html"); + await viewerReady(page); + await openCollection(page, { "a.3md": draftDocument("A"), "b.3md": draftDocument("B") }); + await openedFile(page, "a.3md").click(); + await showEditor(page); + const changed = draftDocument("A", "DraftOnlyNeedle9381"); + await page.fill("#editor", changed); + await openedFile(page, "b.3md").click(); + await page.fill("#findExample", "DraftOnlyNeedle9381"); + await page.locator("#findList button", { hasText: "DraftOnlyNeedle9381" }).click(); + await expect(page.locator("#editor")).toHaveValue(changed); + await page.click("#documentMenu summary"); + await page.click("#packBtn"); + expect(await page.locator("#editor").inputValue()).toContain("DraftOnlyNeedle9381"); + }); + + test("file filtering, keyboard selection, and phone opens reveal the document", async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }); + await page.goto("/viewer.html"); + await viewerReady(page); + await page.getByRole("tab", { name: "Files", exact: true }).click(); + await openCollection(page, { "a.3md": draftDocument("A"), "nested/b.3md": draftDocument("B") }); + await expect(page.locator("#grid")).toHaveAttribute("data-show", "document"); + await page.getByRole("tab", { name: "Files", exact: true }).click(); + await page.fill("#fileFilter", "not-here"); + await expect(page.locator("#fileList")).toContainText("No files match"); + await page.locator("#fileFilter").press("Escape"); + await expect(page.locator("#fileList button")).toHaveCount(2); + await page.locator("#fileFilter").press("ArrowDown"); + await page.keyboard.press("End"); + await expect(openedFile(page, "b.3md")).toBeFocused(); + await page.keyboard.press("Enter"); + await expect(page.locator("#grid")).toHaveAttribute("data-show", "document"); + await expect(page.locator("#sourceName")).toHaveText("b.3md"); + await expect(page.locator("#cubeCanvas")).toBeFocused(); + expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(390); + await page.getByRole("tab", { name: "Files", exact: true }).click(); + await page.fill("#findExample", "Second marker"); + await page.locator("#findList button").filter({ hasText: "Second marker" }).first().click(); + await expect(page.locator("#grid")).toHaveAttribute("data-show", "document"); + expect(await page.evaluate(() => document.getElementById("lab").currentIndex)).toBe(1); + }); + + test("a failed local open preserves the collection and current draft", async ({ page }) => { + await page.goto("/viewer.html"); + await viewerReady(page); + await openCollection(page, { "a.3md": draftDocument("A"), "b.3md": draftDocument("B") }); + await openedFile(page, "a.3md").click(); + await showEditor(page); + const changed = draftDocument("A", "Keep after failed open"); + await page.fill("#editor", changed); + await page.locator("#fileInput").setInputFiles({ name: "broken.3md", mimeType: "text/plain", buffer: Buffer.from("invalid document") }); + await expect(page.locator("#status")).toHaveClass(/err/); + await page.waitForTimeout(350); // A pending editor render must not clear the open error. + await expect(page.locator("#status")).toHaveClass(/err/); + await expect(page.locator("#fileList button")).toHaveCount(2); + await expect(page.locator("#editor")).toHaveValue(changed); + await openedFile(page, "b.3md").click(); + await openedFile(page, "a.3md").click(); + await expect(page.locator("#editor")).toHaveValue(changed); + }); + + test("explicit document navigation removes stale source queries and reloads the chosen source", async ({ page }) => { + const old = draftDocument("Old source"); + await page.route("**/original-document.3md", (route) => route.fulfill({ status: 200, contentType: "text/plain", body: old })); + await page.goto("/viewer.html?src=original-document.3md&theme=dark"); + await viewerReady(page); + await expect(page.locator("#documentTitle")).toHaveText("Old source"); + await page.click("#cubeSample"); + expect(new URL(page.url()).searchParams.has("src")).toBe(false); + expect(new URL(page.url()).searchParams.get("theme")).toBe("dark"); + await page.reload(); + await viewerReady(page); + await expect(page.locator("#documentTitle")).toHaveText("Small sculpture"); + await openCollection(page, { "a.3md": draftDocument("A"), "b.3md": draftDocument("B") }); + await openedFile(page, "b.3md").click(); + await page.reload(); + await viewerReady(page); + await expect(page.locator("#documentTitle")).toHaveText("B"); + }); + }); diff --git a/web/viewer.html b/web/viewer.html index 8433eeb..4897522 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -125,7 +125,12 @@ .edittools{display:none;gap:8px;padding:8px 12px;border-bottom:1px solid var(--hairline);flex-shrink:0} .stage[data-show="edit"] .edittools{display:flex} .edittools .btn{font-size:11px;padding:6px 9px} - .document-title{flex:1;font-size:12px;color:var(--ink);text-transform:none;letter-spacing:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0} + .document-heading{flex:1;min-width:90px;display:flex;align-items:center;gap:8px} + .document-heading>div{min-width:0} + .document-source{display:block;font:10px var(--code-font);color:var(--text-faint);text-transform:none;letter-spacing:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:3px} + .draft-state{font:11px var(--ui-font);color:var(--warning);text-transform:none;letter-spacing:0;flex-shrink:0} + .draft-state[hidden]{display:none} + .document-title{display:block;font-size:12px;color:var(--ink);text-transform:none;letter-spacing:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0} .piecewrap{display:flex;align-items:center;gap:8px;padding:7px 12px;border-bottom:1px solid var(--hairline);font-size:12px} .piecewrap[hidden]{display:none} .piecewrap select{max-width:none;min-width:0;flex:1} @@ -135,7 +140,13 @@ .grid{display:grid;grid-template-columns:minmax(180px,240px) minmax(0,1fr);gap:12px;align-items:stretch;flex:1;min-height:260px} .filelist{overflow:auto;flex:1;min-height:0} .filelist button,.filelist .empty{display:block;width:100%;text-align:left;font:inherit;font-size:12px;font-family:var(--code-font);padding:7px 12px;border:0;border-bottom:1px solid var(--hairline);background:transparent;color:var(--ink)} - .filelist button{cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} + .filelist button{cursor:pointer;position:relative;padding:10px 24px 10px 12px;min-height:44px} + .filelist .file-name,.filelist .file-path{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} + .filelist .file-path{font:10px var(--code-font);color:var(--text-faint);margin-top:4px} + .filelist button[data-edited="true"]::after{content:"";position:absolute;right:12px;top:16px;width:6px;height:6px;border-radius:50%;background:var(--warning)} + .file-filter{margin:10px 12px;min-width:0;font:12px var(--ui-font);color:var(--ink);background:var(--paper);border:1px solid var(--hairline);border-radius:4px;padding:8px 10px} + .file-filter[hidden]{display:none} + .file-filter:focus-visible{outline:2px solid var(--sheen);outline-offset:2px} .filelist button:hover,.filelist button:focus-visible,.filelist button[aria-current="true"]{background:color-mix(in srgb,var(--sheen) 12%,var(--surface));outline:none} .filelist .empty{color:var(--text-faint);font-family:var(--ui-font);line-height:1.6;padding:16px 12px} .filelist .empty strong{display:block;font-size:13px;font-weight:500;color:var(--ink);margin-bottom:6px} @@ -368,6 +379,7 @@

3md viewer.

files
+
@@ -377,8 +389,8 @@

3md viewer.

- Small sculpture - source.3mdLn 1, Col 1 +
Small sculpturesource.3md
+ Ln 1, Col 1 —
+ +
+ +
+ +
+
Slice 1X 1 · Y 1
+
Grid zoom
+
+ +

Arrow keys select a cell. Space applies the current tool.

+
+ +
+
+
Ln 1, Col 1 @@ -639,7 +731,8 @@

3md viewer.

if (chip.left < row.left) outline.scrollLeft -= row.left - chip.left + 13; else if (chip.right > row.right) outline.scrollLeft += chip.right - row.right + 13; } - if (document.getElementById("stage")?.dataset.show === "cubes") drawCubes(); + if (["cubes", "slice"].includes(document.getElementById("stage")?.dataset.show)) drawCubes(); + drawSlice(); const doc = lab.document; if (doc && doc.planes[i]) { planeLive.textContent = `Plane ${i + 1} of ${doc.planes.length}: ${doc.planes[i].label || ("z " + doc.planes[i].z)}`; @@ -678,16 +771,17 @@

3md viewer.

Object.assign(piece.state, { start: ed.selectionStart, end: ed.selectionEnd, scrollTop: ed.scrollTop, scrollLeft: ed.scrollLeft }); } function saveDraft() { + finishSliceStroke(); saveCaret(); const piece = draftPiece(); if (!piece) return; Object.assign(piece.state, { - text: ed.value, plane: lab.currentIndex || 0, + text: currentText(), plane: lab.currentIndex || 0, }); } function updateDraftState() { const piece = draftPiece(); - if (piece && piece.state.text !== ed.value) { piece.state.text = ed.value; lineIndexDirty = true; } + if (piece && normalizeSource(piece.state.text) !== ed.value) { piece.state.text = patchRawSource(piece.state.text, ed.value); lineIndexDirty = true; } document.getElementById("draftState").hidden = !piece || piece.state.text === piece.state.original; document.querySelectorAll("#fileList button").forEach((button) => { const session = fileSessions.get(button.dataset.path); @@ -701,7 +795,7 @@

3md viewer.

// An old ?src= must not win over the document chosen in this session. const url = new URL(location.href); url.searchParams.delete("src"); - url.hash = enc(ed.value); + url.hash = enc(currentText()); history.replaceState(null, "", url); } function revealDocument(focus = false) { @@ -714,8 +808,8 @@

3md viewer.

} function render() { - const src = ed.value; updateDraftState(); + const src = currentText(); counts.textContent = src.split("\n").length + " lines, " + src.length + " chars"; // A delayed editor refresh must keep the slice selected before the refresh. const selectedPlane = lab.currentIndex || 0; @@ -822,7 +916,8 @@

3md viewer.

setIdeStatus(doc, currentCubeVolume(doc).cells.length); } paintNow(); // apply/clear the error-line highlight synchronously - if (document.getElementById("stage")?.dataset.show === "cubes") drawCubes(); + if (["cubes", "slice"].includes(document.getElementById("stage")?.dataset.show)) drawCubes(); + drawSlice(); } // Canonical axes (for the "did you mean" hint) and the full set the renderer @@ -874,7 +969,15 @@

3md viewer.

} let timer = null; - ed.addEventListener("input", () => { openNote = ""; updateDraftState(); paint(); clearTimeout(timer); timer = setTimeout(render, 160); }); + ed.addEventListener("input", (event) => { + recordSourceInput(event.inputType || "replace"); + openNote = ""; updateDraftState(); paint(); clearTimeout(timer); timer = setTimeout(render, 160); + }); + ed.addEventListener("beforeinput", (event) => { + if (["historyUndo", "historyRedo"].includes(event.inputType)) { + event.preventDefault(); moveEditHistory(event.inputType === "historyRedo"); + } + }); ed.addEventListener("scroll", () => { syncScroll(); saveCaret(); }); // Capture before pointer focus leaves Edit; hidden textarea selection differs @@ -886,17 +989,11 @@

3md viewer.

// ---- smart editing keys function setRange(start, end) { ed.selectionStart = start; ed.selectionEnd = end; } - // Apply an edit THROUGH the native undo stack so Ctrl/Cmd+Z works for every - // smart edit. execCommand("insertText") is deprecated but is the only - // cross-engine way to mutate a textarea while preserving (and not corrupting) - // its undo history; setRangeText/value= silently break it. It also fires the - // "input" event itself, which drives paint()/render(). + // Smart edits enter the same draft history as typing and visual strokes. function applyEdit(start, end, text) { ed.focus(); - ed.setSelectionRange(start, end); - let ok = false; - try { ok = document.execCommand("insertText", false, text); } catch (_) {} - if (!ok) { ed.setRangeText(text, start, end, "end"); ed.dispatchEvent(new Event("input")); } + ed.setRangeText(text, start, end, "end"); + ed.dispatchEvent(new InputEvent("input", { inputType: "insertReplacementText", bubbles: true })); } function replaceSel(text) { applyEdit(ed.selectionStart, ed.selectionEnd, text); } function insertAtCursor(snippet, caretBack) { @@ -914,7 +1011,9 @@

3md viewer.

if (e.key !== "Tab" && e.key !== "Shift") tabEscapes = false; // one-shot arm if (mod && (e.key === "s" || e.key === "S")) { e.preventDefault(); document.getElementById("dlBtn").click(); return; } if (mod && e.key === "Enter") { e.preventDefault(); insertPlane(); return; } - if (mod && !e.shiftKey && (e.key === "y" || e.key === "Y")) { e.preventDefault(); ed.focus(); document.execCommand("redo"); return; } + if (mod && ["z", "Z", "y", "Y"].includes(e.key)) { + e.preventDefault(); moveEditHistory(e.shiftKey || e.key.toLowerCase() === "y"); return; + } if (e.key === "Tab") { if (tabEscapes) { tabEscapes = false; return; } // armed: let Tab move focus out e.preventDefault(); @@ -1018,7 +1117,11 @@

3md viewer.

const sourcePath = path && openedFiles.some((file) => file.path === piece.label) ? piece.label : pieces.length === 1 ? path : null; let state = sourcePath && fileDrafts.get(sourcePath); - if (!state) state = { text: piece.text, original: piece.text, start: 0, end: 0, scrollTop: 0, scrollLeft: 0, plane: 0 }; + if (!state) { + const source = sourcePath && openedFiles.find(file => file.path === sourcePath); + const text = source && /\.3md$/i.test(sourcePath) ? source.text : piece.text; + state = { text, original: text, start: 0, end: 0, scrollTop: 0, scrollLeft: 0, plane: 0 }; + } if (sourcePath) fileDrafts.set(sourcePath, state); session.pieces.push({ id: piece.id, label: piece.label, state }); } @@ -1483,7 +1586,7 @@

3md viewer.

// Copy the raw source (agent-friendly: grab the exact document) document.getElementById("copyBtn").addEventListener("click", async () => { - try { await navigator.clipboard.writeText(ed.value); status.className = "status ok"; status.textContent = "Source copied to clipboard."; } + try { await navigator.clipboard.writeText(currentText()); status.className = "status ok"; status.textContent = "Source copied to clipboard."; } catch { status.className = "status err"; status.textContent = "Could not copy (clipboard blocked)."; } }); @@ -1513,7 +1616,7 @@

3md viewer.

}); document.getElementById("kind2Btn").addEventListener("click", () => { try { - const bytes = kind2Bytes(ed.value); + const bytes = kind2Bytes(currentText()); const blob = new Blob([bytes], { type: "application/octet-stream" }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); @@ -1526,7 +1629,7 @@

3md viewer.

} catch (error) { failOpen(error); } }); document.getElementById("dlBtn").addEventListener("click", () => { - const blob = new Blob([ed.value], { type: "text/plain" }); + const blob = new Blob([currentText()], { type: "text/plain" }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); const title = (ed.value.match(/^title:\s*(.+)$/m) || [])[1]; @@ -1538,7 +1641,7 @@

3md viewer.

// Share: put the whole document in the URL hash and copy the link document.getElementById("shareBtn").addEventListener("click", async () => { - const url = location.origin + location.pathname + "#" + enc(ed.value); + const url = location.origin + location.pathname + "#" + enc(currentText()); history.replaceState(null, "", url); try { await navigator.clipboard.writeText(url); status.className = "status ok"; status.textContent = "Share link copied to clipboard."; } catch { status.className = "status ok"; status.textContent = "Share link is in the address bar."; } @@ -1676,7 +1779,7 @@

3md viewer.

"X": [0.94, 0.54, 0.58], ":": [0.52, 0.67, 0.48], "=": [0.87, 0.76, 0.55], "-": [0.49, 0.83, 0.89], }; - const cubeView = { yaw: 0.6, pitch: 0.35, zoom: 1, panX: 0, panY: 0 }; + const cubeView = { yaw: 0.6, pitch: 0.35, zoom: 1, panX: 0, panY: 0, rotation: [0, 0, 0, 1] }; const cubeScene = { doc: undefined, volume: null }; function currentCubeVolume(doc) { if (cubeScene.doc !== doc) { @@ -1960,33 +2063,51 @@

3md viewer.

cubeGpu.count = cells.length; cubePick.points = points; } + const cross3 = (a, b) => [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]]; + const dot3 = (a, b) => a.reduce((sum, value, i) => sum + value * b[i], 0); + function normalizedRotation(q) { + if (!Array.isArray(q) || q.length !== 4 || q.some(value => !Number.isFinite(value))) return [0, 0, 0, 1]; + const largest = Math.max(...q.map(Math.abs)); if (!largest) return [0, 0, 0, 1]; + const scaled = q.map(value => value / largest), length = Math.hypot(...scaled); + return scaled.map(value => value / length); + } + function rotatedAxis(q, axis, radians) { + if (![0,1,2].includes(axis) || !Number.isFinite(radians)) return q; + const angle = radians % (2 * Math.PI) / 2, a = [0, 0, 0]; a[axis] = Math.sin(angle) * (axis === 1 ? -1 : 1); + const w = Math.cos(angle), b = q.slice(0, 3), cross = cross3(a, b); + return normalizedRotation([...b.map((value, i) => w * value + q[3] * a[i] + cross[i]), w * q[3] - dot3(a, b)]); + } + function cameraBasis() { + const cy = Math.cos(cubeView.yaw), sy = Math.sin(cubeView.yaw), cp = Math.cos(cubeView.pitch), sp = Math.sin(cubeView.pitch); + const q = normalizedRotation(cubeView.rotation), v = q.slice(0, 3); + return [[cy,0,-sy],[-sy*sp,cp,-cy*sp],[sy*cp,sp,cy*cp]].map(point => { + const t = cross3(v, point).map(value => 2 * value), c = cross3(v, t); + return point.map((value, i) => value + q[3] * t[i] + c[i]); + }); + } function cubeCamera(width, height, volume, planeCount) { // Sculpt's camera: three extents away, 0.68 of the smaller pane dimension per extent. const extent = Math.max(volume.w, volume.h, planeCount, 1); const dist = extent * 3; const scale = Math.min(width, height) * 0.68 / extent * cubeView.zoom; let tanHalf = height / (2 * scale * dist); - const cp = Math.cos(cubeView.pitch), sp = Math.sin(cubeView.pitch); - const cy = Math.cos(cubeView.yaw), sy = Math.sin(cubeView.yaw); + const [rightAxis, up, back] = cameraBasis(); // Keep the native scale when it fits; leave a margin around small, close cubes. const aspect = width / Math.max(height, 1); let fitHalf = 0; for (const x of [-Math.max(volume.w, 1) / 2, Math.max(volume.w, 1) / 2]) { for (const y of [-Math.max(volume.h, 1) / 2, Math.max(volume.h, 1) / 2]) { for (const z of [-planeCount / 2, planeCount / 2]) { - const right = cy * x - sy * z; - const up = -sy * sp * x + cp * y - cy * sp * z; - const depth = dist - (sy * cp * x + sp * y + cy * cp * z); - fitHalf = Math.max(fitHalf, Math.abs(up) / depth, Math.abs(right) / depth / aspect); + const point = [x,y,z], right = dot3(point,rightAxis), vertical = dot3(point,up); + const depth = dist - dot3(point,back); + fitHalf = Math.max(fitHalf, Math.abs(vertical) / depth, Math.abs(right) / depth / aspect); } } } tanHalf = Math.max(tanHalf, fitHalf * 1.12 / cubeView.zoom); // This camera basis stays continuous through the poles and upside-down views. - const up = [-sy * sp, cp, -cy * sp]; - const target = [cy * cubeView.panX + up[0] * cubeView.panY, - up[1] * cubeView.panY, -sy * cubeView.panX + up[2] * cubeView.panY]; - const eye = [target[0] + sy * cp * dist, target[1] + sp * dist, target[2] + cy * cp * dist]; + const target = rightAxis.map((value, i) => value * cubeView.panX + up[i] * cubeView.panY); + const eye = target.map((value, i) => value + back[i] * dist); const view = lookAt(eye, target, up); const proj = perspective(2 * Math.atan(tanHalf), width / Math.max(height, 1), extent * 0.01, dist + extent * 2); cubePick.eye = eye; @@ -2010,6 +2131,9 @@

3md viewer.

for (const key of ["panX", "panY"]) { cubeView[key] = Number.isFinite(cubeView[key]) ? Math.max(-1000000, Math.min(1000000, cubeView[key])) : 0; } + cubeView.rotation = normalizedRotation(cubeView.rotation); + drawAxisSphere(); + canvas.dataset.rotation = JSON.stringify(cubeView.rotation); const doc = lab.document; const volume = currentCubeVolume(doc); canvas.dataset.cubes = String(volume.cells.length); @@ -2067,6 +2191,312 @@

3md viewer.

cubePick.width = width; cubePick.height = height; } + + const normalizeSource = (text) => text.replace(/\r\n?/g, "\n"); + function rawOffset(text, index) { + let at = 0, normalized = 0; + while (at < text.length && normalized < index) { + if (text[at] === "\r" && text[at + 1] === "\n") at++; + at++; normalized++; + } + return at; + } + function patchRawSource(raw, next) { + const before = normalizeSource(raw); + if (before === next) return raw; + let start = 0, end = 0; + while (start < before.length && start < next.length && before[start] === next[start]) start++; + while (end < before.length - start && end < next.length - start && before[before.length - 1 - end] === next[next.length - 1 - end]) end++; + const newline = raw.match(/\r\n|\r|\n/)?.[0] || "\n"; + return raw.slice(0, rawOffset(raw, start)) + next.slice(start, next.length - end).replace(/\n/g, newline) + + raw.slice(rawOffset(raw, before.length - end)); + } + function currentText() { + const state = draftPiece()?.state; + return state && normalizeSource(state.text) === ed.value ? state.text : ed.value; + } + let historySequence = 0; + function historyState(state = draftPiece()?.state) { + if (!state) return null; + state.undo ||= []; state.redo ||= []; + return state; + } + function editSnapshot(state) { + return { text: state.text, start: ed.selectionStart, end: ed.selectionEnd, plane: lab.currentIndex || 0, + cell: [...(state.cell || [0, 0])], bytes: state.text.length * 2, sequence: ++historySequence }; + } + function trimEditHistory() { + const states = new Set(fileDrafts.values()); + for (const session of fileSessions.values()) for (const piece of session.pieces) states.add(piece.state); + for (const piece of activeSession?.pieces || []) states.add(piece.state); + const entries = []; + for (const state of states) { + historyState(state); + while (state.undo.length + state.redo.length > 100) state.undo.length ? state.undo.shift() : state.redo.shift(); + for (const stack of [state.undo, state.redo]) for (const entry of stack) entries.push({ stack, entry }); + } + let bytes = entries.reduce((total, { entry }) => total + entry.bytes, 0); + entries.sort((a, b) => a.entry.sequence - b.entry.sequence); + for (const { stack, entry } of entries) { + if (bytes <= 8 * 1024 * 1024) break; + stack.splice(stack.indexOf(entry), 1); bytes -= entry.bytes; + } + } + function rememberEdit(state, snapshot = editSnapshot(state)) { + historyState(state).undo.push(snapshot); state.redo = []; state.lastTypingAt = 0; + trimEditHistory(); + } + function recordSourceInput(inputType) { + const state = historyState(); + if (!state || normalizeSource(state.text) === ed.value) return; + const now = performance.now(); + const grouped = inputType === "insertText" && state.lastInputType === inputType && state.lastTypingAt > 0 && now - state.lastTypingAt < 650; + if (!grouped) rememberEdit(state); + state.lastTypingAt = inputType === "insertText" ? now : 0; state.lastInputType = inputType; + } + function moveEditHistory(redo) { + finishSliceStroke(); + const state = historyState(); + if (!state) return; + const entry = (redo ? state.redo : state.undo).pop(); + if (!entry) return; + (redo ? state.undo : state.redo).push(editSnapshot(state)); + state.text = entry.text; state.cell = entry.cell; state.lastTypingAt = 0; + ed.value = state.text; ed.setSelectionRange(entry.start, entry.end); + clearTimeout(timer); render(); + lab.goTo(Math.min(entry.plane, Math.max(0, (lab.document?.planes.length || 1) - 1))); + lineIndexDirty = true; updateDraftState(); drawSlice(); trimEditHistory(); + } + const sliceUI = { tool: "draw", glyph: "#", size: 1, zoom: 1, previous: false, profile: null, text: null, stroke: null, cellSize: 1 }; + const sliceCanvas = document.getElementById("sliceGrid"); + const sliceScroll = document.getElementById("sliceScroll"); + const slicePalette = "#@*+ox:=-"; + function sliceProfile(text) { + const unavailable = (message) => ({ message, grids: [] }); + if (!lab.document || lab.error) return unavailable("Open a valid sculpture to edit its slices. You can correct this document in Edit."); + if (new TextEncoder().encode(text).length > 1.5 * 1024 * 1024 || lab.document.planes.length > 256) return unavailable("This document is larger than the Slice editor supports. Use Edit to keep working with its source."); + const lines = [], expression = /([^\r\n]*)(\r\n|\r|\n|$)/g; + for (let match; (match = expression.exec(text)) && match[0].length;) lines.push({ text: match[1], start: match.index }); + const sections = []; let section = null, fenced = false; + for (const line of lines) { + if (line.text.startsWith("```")) fenced = !fenced; + if (!fenced && /^@plane\s/.test(line.text)) { section = []; sections.push(section); } + else if (section) section.push(line); + } + if (sections.length !== lab.document.planes.length) return unavailable("This document needs explicit slice planes. Use Edit for its current source."); + const grids = []; let width = 0, height = 0, occupied = 0; + for (const lines of sections) { + const begin = lines.findIndex((line) => /^```[^`]*$/.test(line.text)); + const end = begin < 0 ? -1 : lines.findIndex((line, index) => index > begin && /^```\s*$/.test(line.text)); + if (begin < 0 || end < 0) return unavailable("Each slice needs a complete fenced character grid. Use Edit to add or repair one."); + const rows = lines.slice(begin + 1, end); + const w = rows[0]?.text.length || 0; + if (!w || w > 64 || !rows.length || rows.length > 64 || rows.some((row) => row.text.length !== w || /[^.#@*+ox:=\- ]/.test(row.text))) return unavailable("Slice editing supports rectangular grids up to 64 × 64 using Sculpt’s character palette. Use Edit for other content."); + if (grids.length && (w !== width || rows.length !== height)) return unavailable("Slice grids need matching dimensions for visual editing. You can adjust them in Edit."); + width = w; height = rows.length; + const values = rows.map((row) => [...row.text]); + occupied += values.flat().filter((glyph) => glyph !== "." && glyph !== " ").length; + grids.push({ rows, values }); + } + if (!grids.length || occupied > 4000) return unavailable("The Slice editor supports up to 4000 occupied cells. Use Edit for this document."); + return { grids, width, height, occupied, message: null }; + } + function currentSliceProfile() { + if (sliceUI.stroke && !sliceUI.stroke.rejected) return sliceUI.stroke.profile; + const text = currentText(); + if (sliceUI.text !== text) { sliceUI.text = text; sliceUI.profile = sliceProfile(text); } + return sliceUI.profile; + } + function sliceMessage(text = "") { document.getElementById("sliceMessage").textContent = text; } + function drawSlice() { + if (document.getElementById("stage")?.dataset.show !== "slice") return; + const profile = currentSliceProfile(); + document.getElementById("sliceUnavailable").hidden = !profile.message; + document.getElementById("sliceWorkspace").hidden = Boolean(profile.message); + document.getElementById("sliceUnavailable").textContent = profile.message || ""; + if (profile.message) return; + const state = historyState(); + if (!state) return; + const z = Math.min(lab.currentIndex || 0, profile.grids.length - 1); + const cell = state.cell ||= [0, 0]; + cell[0] = Math.max(0, Math.min(cell[0], profile.width - 1)); cell[1] = Math.max(0, Math.min(cell[1], profile.height - 1)); + document.getElementById("sliceHeading").textContent = `Slice ${z + 1} of ${profile.grids.length}`; + document.getElementById("sliceCoordinates").textContent = `X ${cell[0] + 1} · Y ${cell[1] + 1}`; + document.getElementById("sliceDimensions").textContent = `${profile.width} × ${profile.height} cells`; + const list = document.getElementById("sliceList"); + const listKey = currentText() + ":" + z; + if (sliceUI.listKey !== listKey) { + sliceUI.listKey = listKey; list.replaceChildren(); + profile.grids.forEach((grid, index) => { + const button = document.createElement("button"), thumbnail = document.createElement("canvas"), label = document.createElement("span"); + button.className = "slice-thumb"; button.type = "button"; button.setAttribute("aria-label", `Slice ${index + 1}`); + button.setAttribute("aria-current", String(index === z)); button.tabIndex = index === z ? 0 : -1; + thumbnail.width = thumbnail.height = 32; + const ctx = thumbnail.getContext("2d"), unit = 30 / Math.max(profile.width, profile.height); + ctx.fillStyle = "#65b7af"; + grid.values.forEach((row, y) => row.forEach((glyph, x) => { if (glyph !== "." && glyph !== " ") ctx.fillRect(1 + x * unit, 1 + y * unit, unit, unit); })); + label.textContent = String(index + 1); button.append(thumbnail, label); + button.addEventListener("click", () => { finishSliceStroke(); lab.goTo(index); drawSlice(); }); list.append(button); + }); + } + const fit = Math.max(2, Math.floor(Math.min(Math.max(1, sliceScroll.clientWidth - 2) / profile.width, Math.max(1, sliceScroll.clientHeight - 2) / profile.height))); + const unit = fit * sliceUI.zoom; sliceUI.cellSize = unit; + sliceCanvas.width = Math.ceil(profile.width * unit); sliceCanvas.height = Math.ceil(profile.height * unit); + sliceCanvas.style.width = sliceCanvas.width + "px"; sliceCanvas.style.height = sliceCanvas.height + "px"; + sliceCanvas.dataset.x = cell[0]; sliceCanvas.dataset.y = cell[1]; sliceCanvas.dataset.slice = z; + sliceCanvas.setAttribute("aria-rowcount", profile.height); sliceCanvas.setAttribute("aria-colcount", profile.width); + sliceCanvas.setAttribute("aria-label", `Slice ${z + 1} character grid, X ${cell[0] + 1}, Y ${cell[1] + 1}, ${sliceUI.tool} with ${sliceUI.glyph}`); + const ctx = sliceCanvas.getContext("2d"); + ctx.font = `${Math.max(7, unit * 0.6)}px Spline Sans Mono, monospace`; ctx.textAlign = "center"; ctx.textBaseline = "middle"; + profile.grids[z].values.forEach((row, y) => row.forEach((glyph, x) => { + ctx.fillStyle = (x + y) % 2 ? "#202729" : "#1c2325"; ctx.fillRect(x * unit, y * unit, unit - 0.5, unit - 0.5); + if (glyph !== "." && glyph !== " ") { ctx.fillStyle = "#e3eeed"; ctx.fillText(glyph, (x + 0.5) * unit, (y + 0.5) * unit); } + else if (sliceUI.previous && z > 0) { + const previous = profile.grids[z - 1].values[y][x]; + if (previous !== "." && previous !== " ") { ctx.fillStyle = "#58847d"; ctx.fillText(previous, (x + 0.5) * unit, (y + 0.5) * unit); } + } + })); + ctx.strokeStyle = "#39cbbb"; ctx.lineWidth = 2; ctx.strokeRect(cell[0] * unit + 1, cell[1] * unit + 1, unit - 2, unit - 2); + const previous = document.getElementById("slicePrevious"); previous.disabled = z === 0; previous.checked = sliceUI.previous && z > 0; + for (const [id, value, max] of [["sliceX", cell[0] + 1, profile.width], ["sliceY", cell[1] + 1, profile.height]]) { + const field = document.getElementById(id); field.max = max; if (document.activeElement !== field) field.value = value; + } + document.getElementById("sliceUndo").disabled = !state.undo.length; + document.getElementById("sliceRedo").disabled = !state.redo.length; + document.getElementById("slicePalette").hidden = sliceUI.tool === "erase"; + document.getElementById("sliceSize").hidden = sliceUI.tool === "fill"; + document.getElementById("sliceToolHint").textContent = sliceUI.tool === "fill" ? "Fill a connected region of matching characters." : sliceUI.tool === "erase" ? "Drag to erase from this slice." : `Drag to draw with ${sliceUI.glyph}.`; + document.getElementById("sliceReferenceNote").textContent = document.getElementById("cubeCanvas").dataset.renderer === "none" ? "3D reference needs WebGL2. Slice editing is available." : profile.occupied ? "Drag the reference to orbit. Scroll to zoom." : "Draw a character to see it in 3D."; + } + function sliceLine(start, end) { + let [x, y] = start; const dx = Math.abs(end[0] - x), dy = -Math.abs(end[1] - y), sx = x < end[0] ? 1 : -1, sy = y < end[1] ? 1 : -1; + let error = dx + dy; const result = []; + while (true) { result.push([x, y]); if (x === end[0] && y === end[1]) return result; + const twice = 2 * error; if (twice >= dy) { error += dy; x += sx; } if (twice <= dx) { error += dx; y += sy; } + } + } + function beginSliceStroke(pointerId = null) { + finishSliceStroke(); const profile = currentSliceProfile(), state = historyState(); + if (!state || profile.message) return false; + sliceMessage(); + sliceUI.stroke = { profile, state, pointerId, original: state.text, snapshot: editSnapshot(state), last: null, changed: false, rejected: false, redo: state.redo, tool: sliceUI.tool, glyph: sliceUI.glyph, size: sliceUI.size, z: lab.currentIndex || 0 }; + return true; + } + function paintSliceCell(cell) { + const stroke = sliceUI.stroke; + if (!stroke || stroke.rejected || stroke.state !== draftPiece()?.state) return; + const { profile } = stroke, grid = profile.grids[stroke.z], points = []; + if (stroke.tool === "fill") { + if (stroke.last) return; + const previous = grid.values[cell[1]][cell[0]].replace(" ", "."), visited = new Set(); const queue = [cell]; + for (let i = 0; i < queue.length; i++) { + const [x, y] = queue[i], key = y * profile.width + x; + if (x < 0 || y < 0 || x >= profile.width || y >= profile.height || visited.has(key)) continue; + visited.add(key); if (grid.values[y][x].replace(" ", ".") !== previous) continue; + points.push([x, y]); queue.push([x - 1, y], [x + 1, y], [x, y - 1], [x, y + 1]); + } + } else { + const radius = Math.floor(stroke.size / 2); + for (const [x, y] of sliceLine(stroke.last || cell, cell)) for (let row = y - radius; row <= y + radius; row++) for (let col = x - radius; col <= x + radius; col++) { + if (col >= 0 && row >= 0 && col < profile.width && row < profile.height) points.push([col, row]); + } + } + stroke.last = cell; stroke.state.cell = cell; + const glyph = stroke.tool === "erase" ? "." : stroke.glyph; + let changed = false; + for (const [x, y] of points) { + const before = grid.values[y][x]; if (before === glyph || (glyph === "." && before === " ")) continue; + profile.occupied += (glyph !== "." ? 1 : 0) - (before !== "." && before !== " " ? 1 : 0); + grid.values[y][x] = glyph; changed = true; + } + if (profile.occupied > 4000) { + if (stroke.changed) { const index = stroke.state.undo.indexOf(stroke.snapshot); if (index >= 0) stroke.state.undo.splice(index, 1); stroke.state.redo = stroke.redo; } + stroke.state.text = stroke.original; ed.value = stroke.original; stroke.rejected = true; + sliceUI.text = null; render(); sliceMessage("This edit would exceed 4000 occupied cells. The stroke was restored."); return; + } + if (changed) { + if (!stroke.changed) { rememberEdit(stroke.state, stroke.snapshot); stroke.changed = true; } + const edits = grid.rows.map((row, y) => ({ start: row.start, end: row.start + row.text.length, text: grid.values[y].join("") })); + let text = stroke.original; for (const edit of edits.reverse()) text = text.slice(0, edit.start) + edit.text + text.slice(edit.end); + stroke.state.text = text; ed.value = text; lineIndexDirty = true; updateDraftState(); + if (!sliceUI.renderQueued) { sliceUI.renderQueued = true; requestAnimationFrame(() => { sliceUI.renderQueued = false; render(); }); } + } + drawSlice(); + } + function finishSliceStroke() { + if (!sliceUI.stroke) return; + sliceUI.stroke = null; sliceUI.text = null; + } + function sliceCellAt(event) { + const rect = sliceCanvas.getBoundingClientRect(), profile = currentSliceProfile(); + if (profile.message) return null; + const x = Math.floor((event.clientX - rect.left) / sliceUI.cellSize), y = Math.floor((event.clientY - rect.top) / sliceUI.cellSize); + return x >= 0 && y >= 0 && x < profile.width && y < profile.height ? [x, y] : null; + } + sliceCanvas.addEventListener("pointerdown", (event) => { + if (event.button !== 0 || event.isPrimary === false || sliceUI.stroke) return; + const cell = sliceCellAt(event); if (!cell || !beginSliceStroke(event.pointerId)) return; + event.preventDefault(); sliceCanvas.focus({ preventScroll: true }); + try { sliceCanvas.setPointerCapture(event.pointerId); } catch (_) {} + paintSliceCell(cell); + }); + sliceCanvas.addEventListener("pointermove", (event) => { + if (sliceUI.stroke?.pointerId !== event.pointerId) return; + const cell = sliceCellAt(event); if (cell) paintSliceCell(cell); + }); + for (const type of ["pointerup", "pointercancel", "lostpointercapture"]) sliceCanvas.addEventListener(type, (event) => { + if (sliceUI.stroke?.pointerId === event.pointerId) { finishSliceStroke(); drawSlice(); } + }); + sliceCanvas.addEventListener("keydown", (event) => { + if ((event.metaKey || event.ctrlKey) && ["z", "y"].includes(event.key.toLowerCase())) { event.preventDefault(); moveEditHistory(event.shiftKey || event.key.toLowerCase() === "y"); return; } + const state = historyState(), profile = currentSliceProfile(); if (!state || profile.message) return; + const cell = [...(state.cell || [0, 0])]; + if (event.key === "ArrowLeft") cell[0]--; else if (event.key === "ArrowRight") cell[0]++; + else if (event.key === "ArrowUp") cell[1]--; else if (event.key === "ArrowDown") cell[1]++; + else if (event.key === " ") { event.preventDefault(); if (beginSliceStroke()) { paintSliceCell(cell); finishSliceStroke(); drawSlice(); } return; } + else return; + event.preventDefault(); cell[0] = Math.max(0, Math.min(cell[0], profile.width - 1)); cell[1] = Math.max(0, Math.min(cell[1], profile.height - 1)); state.cell = cell; drawSlice(); + const unit = sliceUI.cellSize; if (cell[0] * unit < sliceScroll.scrollLeft) sliceScroll.scrollLeft = cell[0] * unit; + if ((cell[0] + 1) * unit > sliceScroll.scrollLeft + sliceScroll.clientWidth) sliceScroll.scrollLeft = (cell[0] + 1) * unit - sliceScroll.clientWidth; + if (cell[1] * unit < sliceScroll.scrollTop) sliceScroll.scrollTop = cell[1] * unit; + if ((cell[1] + 1) * unit > sliceScroll.scrollTop + sliceScroll.clientHeight) sliceScroll.scrollTop = (cell[1] + 1) * unit - sliceScroll.clientHeight; + }); + for (const [id, key, attribute] of [["sliceTool", "tool", "tool"], ["sliceSize", "size", "size"], ["sliceZoom", "zoom", "zoom"]]) { + document.getElementById(id).addEventListener("click", (event) => { + const button = event.target.closest("button"); if (!button) return; finishSliceStroke(); + sliceUI[key] = key === "tool" ? button.dataset[attribute] : Number(button.dataset[attribute]); + for (const item of button.parentElement.querySelectorAll("button")) item.setAttribute("aria-pressed", String(item === button)); drawSlice(); + }); + } + for (const glyph of slicePalette) { + const button = document.createElement("button"); button.type = "button"; button.className = "btn"; button.textContent = glyph; + button.setAttribute("aria-label", `Paint ${glyph}`); button.setAttribute("aria-pressed", String(glyph === sliceUI.glyph)); + button.addEventListener("click", () => { finishSliceStroke(); sliceUI.glyph = glyph; + for (const item of button.parentElement.children) item.setAttribute("aria-pressed", String(item === button)); drawSlice(); }); document.getElementById("slicePalette").append(button); + } + document.getElementById("slicePrevious").addEventListener("change", (event) => { sliceUI.previous = event.target.checked; drawSlice(); }); + for (const id of ["sliceX", "sliceY"]) document.getElementById(id).addEventListener("change", () => { + const profile = currentSliceProfile(), x = Number(document.getElementById("sliceX").value) - 1, y = Number(document.getElementById("sliceY").value) - 1; + if (!profile.message && Number.isInteger(x) && Number.isInteger(y) && x >= 0 && y >= 0 && x < profile.width && y < profile.height) { + historyState().cell = [x,y]; drawSlice(); + } else sliceMessage("Choose X and Y inside the current grid."); + }); + document.getElementById("sliceApply").addEventListener("click", () => { + const x = Number(document.getElementById("sliceX").value) - 1, y = Number(document.getElementById("sliceY").value) - 1, profile = currentSliceProfile(); + if (profile.message || !Number.isInteger(x) || !Number.isInteger(y) || x < 0 || y < 0 || x >= profile.width || y >= profile.height) { sliceMessage("Choose X and Y inside the current grid."); return; } + if (beginSliceStroke()) { paintSliceCell([x, y]); finishSliceStroke(); drawSlice(); } + }); + document.getElementById("sliceUndo").addEventListener("click", () => moveEditHistory(false)); + document.getElementById("sliceRedo").addEventListener("click", () => moveEditHistory(true)); + document.getElementById("sliceExpand").addEventListener("click", () => document.getElementById("cubesTab").click()); + document.getElementById("sliceList").addEventListener("keydown", (event) => { + const buttons = [...event.currentTarget.children], current = buttons.indexOf(document.activeElement); + if (current < 0 || !["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key)) return; + event.preventDefault(); const index = event.key === "Home" ? 0 : event.key === "End" ? buttons.length - 1 : Math.max(0, Math.min(buttons.length - 1, current + (["ArrowUp", "ArrowLeft"].includes(event.key) ? -1 : 1))); + finishSliceStroke(); lab.goTo(index); drawSlice(); document.getElementById("sliceList").children[index]?.focus(); + }); + new ResizeObserver(() => drawSlice()).observe(sliceScroll); + const grid = document.getElementById("grid"); const stage = document.getElementById("stage"); function selectTab(root, tab, apply) { @@ -2100,12 +2530,20 @@

3md viewer.

stage.dataset.show = pane; document.querySelector(".wrap").dataset.view = pane; if (pane === "preview" && lab.render) lab.render(); - if (pane === "cubes") requestAnimationFrame(drawCubes); + finishSliceStroke(); + const canvas = document.getElementById("cubeCanvas"); + if (pane === "slice") { + document.getElementById("sliceReference").appendChild(canvas); + requestAnimationFrame(() => { drawSlice(); drawCubes(); }); + } else { + document.getElementById("cubesPane").prepend(canvas); + if (pane === "cubes") requestAnimationFrame(drawCubes); + } }); wireTabs(document.querySelector(".fileswitch"), (pane) => { grid.dataset.show = pane; if (pane === "document" && stage.dataset.show === "preview" && lab.render) lab.render(); - if (pane === "document" && stage.dataset.show === "cubes") requestAnimationFrame(drawCubes); + if (pane === "document" && ["cubes", "slice"].includes(stage.dataset.show)) requestAnimationFrame(() => { drawSlice(); drawCubes(); }); }); const cubeCanvas = document.getElementById("cubeCanvas"); function zoomCubes(factor) { @@ -2118,6 +2556,7 @@

3md viewer.

cubeView.zoom = 1; cubeView.panX = 0; cubeView.panY = 0; + cubeView.rotation = [0,0,0,1]; drawCubes(); } function panCubes(dx, dy) { @@ -2126,6 +2565,57 @@

3md viewer.

cubeView.panY += dy * scale; drawCubes(); } + let selectedAxis = null; + function chooseAxis(axis) { + selectedAxis = axis; chooseCubeTool("orbit"); + document.querySelectorAll("#axisButtons button").forEach(button => button.setAttribute("aria-pressed", String(button.dataset.axis === (axis === null ? "free" : String(axis))))); + for (const id of ["axisMinus", "axisPlus"]) document.getElementById(id).disabled = axis === null; + document.getElementById("axisHint").textContent = axis === null ? "Choose X, Y or Z." : `Rotate around ${"XYZ"[axis]}.`; + cubeCanvas.dataset.axis = axis === null ? "free" : "XYZ"[axis]; drawAxisSphere(); + } + function drawAxisSphere() { + const [right,up] = cameraBasis(); + document.querySelectorAll("#axisSphere path").forEach(path => { + const axis = Number(path.dataset.axis), other = [0,1,2].filter(value => value !== axis); + const points = Array.from({length:65}, (_, i) => { + const point = [0,0,0], angle = i * Math.PI / 32; point[other[0]] = Math.cos(angle); point[other[1]] = Math.sin(angle); point[1] *= -1; + return `${i ? "L" : "M"}${50+34*dot3(point,right)},${50-34*dot3(point,up)}`; + }); + path.setAttribute("d", points.join(" ")); path.classList.toggle("selected", selectedAxis === axis); + }); + } + document.querySelectorAll("#axisButtons button").forEach(button => button.addEventListener("click", () => chooseAxis(button.dataset.axis === "free" ? null : Number(button.dataset.axis)))); + function validStep(id) { + const field = document.getElementById(id), value = Number(field.value), valid = field.value.trim() && Number.isFinite(value) && value > 0; + field.setAttribute("aria-invalid", String(!valid)); document.getElementById("precisionMessage").textContent = valid ? "" : "Enter a finite, positive step."; + return valid ? value : null; + } + for (const [id, sign] of [["axisMinus",-1],["axisPlus",1]]) document.getElementById(id).addEventListener("click", () => { + const step = validStep("rotationStep"); if (step === null || selectedAxis === null) return; + cubeView.rotation = rotatedAxis(cubeView.rotation, selectedAxis, sign * (step % 360) * Math.PI / 180); drawCubes(); + }); + document.querySelectorAll("[data-pan]").forEach(button => button.addEventListener("click", () => { + const step = validStep("panStep"); if (step === null) return; const [x,y] = button.dataset.pan.split(",").map(Number); + cubeView.panX -= x * step; cubeView.panY += y * step; drawCubes(); + })); + let sphereDrag = null; + const sphere = document.querySelector("#axisSphere svg"); + sphere.addEventListener("pointerdown", event => { + if (event.button !== 0 || event.isPrimary === false) return; + const rect = sphere.getBoundingClientRect(), x = (event.clientX-rect.left)*100/rect.width, y = (event.clientY-rect.top)*100/rect.height; + let nearest = { distance: Infinity, axis: 0 }; + document.querySelectorAll("#axisSphere path").forEach(path => { + for (let at=0, length=path.getTotalLength(); at<=length; at+=2) { const p=path.getPointAtLength(at), distance=Math.hypot(x-p.x,y-p.y); if(distance { + if (sphereDrag?.id !== event.pointerId) return; + const dx=event.clientX-sphereDrag.x, dy=event.clientY-sphereDrag.y; + cubeView.rotation=rotatedAxis(sphereDrag.rotation,sphereDrag.axis,(Math.abs(dx)>=Math.abs(dy)?dx:-dy)*.008); drawCubes(); + }); + for(const type of ["pointerup","pointercancel","lostpointercapture"]) sphere.addEventListener(type, () => {sphereDrag=null;}); let cubeTool = "orbit"; function chooseCubeTool(tool) { cubeTool = tool; @@ -2147,6 +2637,9 @@

3md viewer.

panCubes(event.key === "ArrowLeft" ? -24 : event.key === "ArrowRight" ? 24 : 0, event.key === "ArrowUp" ? -24 : event.key === "ArrowDown" ? 24 : 0); } + else if (selectedAxis !== null && ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(event.key)) { + cubeView.rotation = rotatedAxis(cubeView.rotation, selectedAxis, ["ArrowRight", "ArrowUp"].includes(event.key) ? 0.12 : -0.12); drawCubes(); + } else if (event.key === "ArrowLeft") { cubeView.yaw -= 0.12; drawCubes(); } else if (event.key === "ArrowRight") { cubeView.yaw += 0.12; drawCubes(); } else if (event.key === "ArrowUp") { cubeView.pitch += 0.12; drawCubes(); } @@ -2164,7 +2657,7 @@

3md viewer.

const cubePointers = new Map(); function startCubeDrag(event, moved = false) { cubeDrag = { pointerId: event.pointerId, x: event.clientX, y: event.clientY, - yaw: cubeView.yaw, pitch: cubeView.pitch, panX: cubeView.panX, panY: cubeView.panY, + yaw: cubeView.yaw, pitch: cubeView.pitch, rotation: [...cubeView.rotation], axis: selectedAxis, panX: cubeView.panX, panY: cubeView.panY, scale: cubePick.worldPerPixel || 0, moved, tool: cubeTool === "pan" || event.shiftKey || event.button === 1 || event.button === 2 ? "pan" : "orbit" }; } @@ -2204,6 +2697,8 @@

3md viewer.

if (cubeDrag.tool === "pan") { cubeView.panX = cubeDrag.panX - dx * cubeDrag.scale; cubeView.panY = cubeDrag.panY + dy * cubeDrag.scale; + } else if (cubeDrag.axis !== null) { + cubeView.rotation = rotatedAxis(cubeDrag.rotation, cubeDrag.axis, (Math.abs(dx) >= Math.abs(dy) ? dx : -dy) * 0.008); } else { cubeView.yaw = cubeDrag.yaw - dx * 0.008; cubeView.pitch = cubeDrag.pitch + dy * 0.008; @@ -2218,9 +2713,8 @@

3md viewer.

const sx = ((event.clientX - rect.left) / cubePick.width * 2 - 1) * cubePick.tanHalf * cubePick.width / cubePick.height; const sy = (1 - (event.clientY - rect.top) / cubePick.height * 2) * cubePick.tanHalf; - const cy = Math.cos(cubeView.yaw), syaw = Math.sin(cubeView.yaw); - const cp = Math.cos(cubeView.pitch), sp = Math.sin(cubeView.pitch); - const ray = [cy * sx - syaw * sp * sy - syaw * cp, cp * sy - sp, -syaw * sx - cy * sp * sy - cy * cp]; + const [right, up, back] = cameraBasis(); + const ray = right.map((value, i) => value * sx + up[i] * sy - back[i]); let best = null; for (const point of cubePick.points) { let near = 0, far = Infinity; @@ -2257,7 +2751,7 @@

3md viewer.

}, { passive: false }); if (window.ResizeObserver) { new ResizeObserver(() => { - if (stage.dataset.show === "cubes") drawCubes(); + if (["cubes", "slice"].includes(stage.dataset.show)) drawCubes(); }).observe(cubeCanvas); } document.getElementById("cubeSample").addEventListener("click", () => { @@ -2292,7 +2786,7 @@

3md viewer.

}; } window.threeMd = { - set(src) { ready(); ed.value = String(src); render(); updateCursor(); return snapshot(); }, + set(src) { ready(); finishSliceStroke(); if (draftPiece()) draftPiece().state.text = String(src); ed.value = String(src); render(); updateCursor(); return snapshot(); }, // Side-effect-free: parses `src` and restores the live editor document after. validate(src) { ready(); @@ -2303,7 +2797,7 @@

3md viewer.

return result; }, get document() { ready(); return lab.document; }, - get source() { return ed.value; }, + get source() { return currentText(); }, }; if (window.customElements) customElements.whenDefined("three-md").then(init); From c86a777aa255ae3f36341ab2b684dc3896f5606c Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:03:40 -0600 Subject: [PATCH 27/43] Record actual parity verification and materialize Slice requirements --- .../state.json | 3 +- .../tasks.md | 2 +- .../testing.md | 10 + .../state.json | 3 +- .../tasks.md | 2 +- .../testing.md | 13 +- docs/evidence/viewer-slice/README.md | 2 + .../attestation-implementation.json | 1 + .../provenance-implementation.json | 1 + .../viewer-slice/trust-implementation.log | 1497 +++++++++++++++++ specs/ThreeMDViewer/ThreeMDViewer.spec.md | 4 +- specs/ThreeMDViewer/requirements.md | 35 +- 12 files changed, 1563 insertions(+), 10 deletions(-) create mode 100644 docs/evidence/viewer-slice/attestation-implementation.json create mode 100644 docs/evidence/viewer-slice/provenance-implementation.json create mode 100644 docs/evidence/viewer-slice/trust-implementation.log diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json index e9eec55..f51262c 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json @@ -8,9 +8,10 @@ "description": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", "kind": "feature", "state": "implementing", + "canonical_applied": true, "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", "created_at": 1791644309, - "updated_at": 1791653029, + "updated_at": 1791655390, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md index 609251b..29b3dcc 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md @@ -10,4 +10,4 @@ artifact: tasks - [x] Add native and browser sphere/constraint/step controls. - [x] Verify numerical, picking, geometry and input parity. - [x] Synchronize contracts and intent. -- [ ] Record current verification and complete approved lifecycle closure. +- [x] Record current verification and prepare approved lifecycle closure. diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md index 684642d..5739bed 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md @@ -6,3 +6,13 @@ artifact: testing # Testing Test each document axis with positive, negative and full-turn rotations, including Z roll and pole crossings. Compare native live, scalar and browser projected points and nearest cube hits. Assert inverse steps restore the same basis, invalid inputs do not mutate the camera, camera adjustments preserve document and geometry, and mobile and keyboard controls stay usable. Run the relevant native and Chromium/WebKit regressions and current trust gate after implementation. + +## Execution evidence + +Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux and final lifecycle receipts are recorded in docs/evidence/viewer-slice. Source and visual verification are distinct from Leif’s diff review. + +## Requirement evidence + +| ID | Canonical | Evidence | +| --- | --- | --- | +| REQ-ThreeMDViewer-007 | REQ-ThreeMDViewer-007 | Independent shared camera-parity.json matrix/projection values compared with browser GPU uniforms and nearest picks, native scalar/live basis and picks, full-turn/inverse normalization, ASCII Z picking and mesh installation reuse. Browser precise-input and phone tests pass; native/UI screenshots and logs are in docs/evidence/viewer-slice. | diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json index b70f088..0a2b736 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json @@ -8,9 +8,10 @@ "description": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", "kind": "feature", "state": "implementing", + "canonical_applied": true, "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", "created_at": 1791652000, - "updated_at": 1791653022, + "updated_at": 1791655366, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md index d31a0c7..c331b90 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md @@ -14,6 +14,6 @@ artifact: tasks - [x] Verify shared native/browser edit fixtures and preserve existing camera/file/export behavior. - [x] Verify desktop, phone, keyboard, touch, canceled-pointer and GPU-unavailable behavior. - [x] Synchronize canonical contracts and human intent with the resulting implementation. -- [ ] Run pinned Trust, record actual provenance and present verification evidence. +- [x] Run pinned Trust, record actual provenance and present verification evidence. Lifecycle acceptance/archive and PR update require the recorded verified-closure authority and passing current verification. Scope approval is not an independent review or a permitted signature. diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md index 038d85a..0c664a1 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md @@ -13,4 +13,15 @@ History checks mix source typing, insert tools, grid strokes and undo/redo; swit Chromium/WebKit checks cover desktop and 390x844/320x740 layouts, primary touch drawing, keyboard cell movement and Space, explicit X/Y validation, every zoom option and previous-slice visibility. Require internal grid scrolling, visible controls and meaningful accessibility names. GPU-unavailable Slice editing remains usable. Existing one-context, no camera-only geometry upload, nearest picking and pole-crossing tests run unchanged. -Run the complete viewer suite on macOS and the complete UI suite in the existing Linux Playwright environment. Run the focused native workspace fixture selection and broaden native tests only if behavior or failures warrant it. Run strict root and nested app specs with full configured coverage, root/native Hi and pinned Trust 1.2.2 with Fledge 1.7.2. Record actual actor, tested source commit, retries/skips and unchanged provenance limits. No tests or visual approval are claimed yet. +Run the complete viewer suite on macOS and the complete UI suite in the existing Linux Playwright environment. Run the focused native workspace fixture selection and broaden native tests only if behavior or failures warrant it. Run strict root and nested app specs with full configured coverage, root/native Hi and pinned Trust 1.2.2 with Fledge 1.7.2. Record actual actor, tested source commit, retries/skips and unchanged provenance limits. Actual execution evidence is recorded under docs/evidence/viewer-slice. No independent human review or permitted signature is claimed. + +## Execution evidence + +Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux and final lifecycle receipts are recorded in docs/evidence/viewer-slice. Source and visual verification are distinct from Leif’s diff review. + +## Requirement evidence + +| ID | Canonical | Evidence | +| --- | --- | --- | +| REQ-ThreeMDViewer-003 | REQ-ThreeMDViewer-003 | Actual four-view layout in web/viewer.html; full Chromium/WebKit viewer regressions and desktop/phone screenshots in docs/evidence/viewer-slice. | +| REQ-ThreeMDViewer-008 | REQ-ThreeMDViewer-008 | Shared slice-parity.json cases run by browser pointer gestures and native browserSliceFixturesMatchNativeWorkspaceToolsAndWholeStrokeHistory. Source preservation, bounded history, navigation, keyboard, downloads, GPU refusal and phone tests pass; actual logs are in docs/evidence/viewer-slice. | diff --git a/docs/evidence/viewer-slice/README.md b/docs/evidence/viewer-slice/README.md index 5b4b1c5..b510a0c 100644 --- a/docs/evidence/viewer-slice/README.md +++ b/docs/evidence/viewer-slice/README.md @@ -18,3 +18,5 @@ Slice preserves raw non-target text, including CRLF, fractional plane positions, The browser’s supported edit profile is complete common rectangular grids up to 64×64, 256 planes, 4000 occupied cells and 1.5 MiB source, with the native palette and dot/space empties. Structural slice actions, volume resizing and browser 3D painting remain subsequent work. Native storage, formats, library APIs, examples, generated browser bundles and releases are unchanged. Linux, final Trust and lifecycle receipts are recorded after their current runs complete. Actual reviewer identity is agent:codex. Scope and conditional verified closure were directly authorized by Leif; that does not supply a permitted signature or a human diff review. Existing soft unsigned provenance policy remains intact. + +Implementation commit: `8e9a0c4`. Pinned Trust 1.2.2 / Fledge 1.7.2 passed (`trust-implementation.log`). Actual unsigned agent:codex record and unchanged policy result are in `attestation-implementation.json` and `provenance-implementation.json`; the strict provenance policy fails for the unsigned/unpermitted reviewer, while Trust’s configured soft mode passes with progressive provenance. No policy was changed. diff --git a/docs/evidence/viewer-slice/attestation-implementation.json b/docs/evidence/viewer-slice/attestation-implementation.json new file mode 100644 index 0000000..542cae9 --- /dev/null +++ b/docs/evidence/viewer-slice/attestation-implementation.json @@ -0,0 +1 @@ +{"commit":"8e9a0c4eecfa50b8918b864b3569c1dec5fde559","confidence":0.86,"humanApproved":false,"note":"Actual Codex implementation and review claim: Slice and three-axis camera parity passed macOS browser, native broad and final focused checks; pinned Trust passed. Leif authorized scope and conditional closure, not a diff review. No permitted signature or independent human approval is claimed.","reviewer":"agent:codex","testsPassed":true,"timestamp":1791655286,"verdict":"review"} diff --git a/docs/evidence/viewer-slice/provenance-implementation.json b/docs/evidence/viewer-slice/provenance-implementation.json new file mode 100644 index 0000000..6990f11 --- /dev/null +++ b/docs/evidence/viewer-slice/provenance-implementation.json @@ -0,0 +1 @@ +{"checkedCommits":1,"passed":false,"violations":[{"commit":"8e9a0c4eecfa50b8918b864b3569c1dec5fde559","detail":"no valid signed attestation","rule":"requireSignature"},{"commit":"8e9a0c4eecfa50b8918b864b3569c1dec5fde559","detail":"reviewer agent:codex is not in the allow-list [\"agent:claude\", \"human:\"]","rule":"allowedReviewers"}]} diff --git a/docs/evidence/viewer-slice/trust-implementation.log b/docs/evidence/viewer-slice/trust-implementation.log new file mode 100644 index 0000000..b2ed0e0 --- /dev/null +++ b/docs/evidence/viewer-slice/trust-implementation.log @@ -0,0 +1,1497 @@ +▶️ Lane: verify — Three language suites, nine-pair public-package interchange, generated bundle drift and editor grammar. Trust runs SpecSync after this lane. + ▶️ Running task: lint + ✔ Step 1 done (576ms) + ▶️ Running task: build +Building for debugging... +[0/5] Write swift-version--58304C5D6DBC2206.txt +Build complete! (0.13s) + ✔ Step 2 done (617ms) + ▶️ Running task: test +[0/1] Planning build +Building for debugging... +[0/6] Write swift-version--58304C5D6DBC2206.txt +Build complete! (0.21s) +Test Suite 'All tests' started at 2026-10-10 11:55:29.448. +Test Suite '3mdPackageTests.xctest' started at 2026-10-10 11:55:29.450. +Test Suite 'CompositionEditingTests' started at 2026-10-10 11:55:29.450. +Test Case '-[ThreeMDTests.CompositionEditingTests testCancelledGraphTransactionPropagatesCancellation]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testCancelledGraphTransactionPropagatesCancellation]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testEntryReplacementKeepsIDAndCanEditSharedDefinitionWithoutFlattening]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testEntryReplacementKeepsIDAndCanEditSharedDefinitionWithoutFlattening]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testFinalGraphValidationAllowsForwardReferenceInsertionAndRootReplacement]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testFinalGraphValidationAllowsForwardReferenceInsertionAndRootReplacement]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphRevisionIncludesReferenceOrderAttributesAndRootAndSurvivesReopen]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphRevisionIncludesReferenceOrderAttributesAndRootAndSurvivesReopen]' passed (0.008 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphSnapshotsAndPatchesAreCodableAndDecodedGraphsStillValidate]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphSnapshotsAndPatchesAreCodableAndDecodedGraphsStillValidate]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphTransactionBoundsOperationsPayloadAndDefinitions]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphTransactionBoundsOperationsPayloadAndDefinitions]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testMissingTargetAndCycleFailuresHaveGraphPathsWithoutPartialPublication]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testMissingTargetAndCycleFailuresHaveGraphPathsWithoutPartialPublication]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceIdentityCannotChangeOrBeDuplicatedWithinOwner]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceIdentityCannotChangeOrBeDuplicatedWithinOwner]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceRetargetMoveAndRemoveKeepInstanceIdentityAndOpaqueAttributes]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceRetargetMoveAndRemoveKeepInstanceIdentityAndOpaqueAttributes]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testRemovingAndRewritingReferencesValidatesOnlyCompleteFinalGraph]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testRemovingAndRewritingReferencesValidatesOnlyCompleteFinalGraph]' passed (0.002 seconds). +Test Suite 'CompositionEditingTests' passed at 2026-10-10 11:55:29.486. + Executed 10 tests, with 0 failures (0 unexpected) in 0.035 (0.036) seconds +Test Suite 'ConformanceTests' started at 2026-10-10 11:55:29.486. +Test Case '-[ThreeMDTests.ConformanceTests testConformanceVectors]' started. +Test Case '-[ThreeMDTests.ConformanceTests testConformanceVectors]' passed (0.010 seconds). +Test Suite 'ConformanceTests' passed at 2026-10-10 11:55:29.496. + Executed 1 test, with 0 failures (0 unexpected) in 0.010 (0.010) seconds +Test Suite 'CrossPlaneLinkHTMLTests' started at 2026-10-10 11:55:29.496. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testAnchorHrefMatchesSectionId]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testAnchorHrefMatchesSectionId]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDecimalTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDecimalTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDefaultTextIsEscaped]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDefaultTextIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorEmptyText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorEmptyText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNegativeTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNegativeTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNoText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNoText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorScientificNotation]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorScientificNotation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorTextIsEscaped]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorTextIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorWithText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorWithText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testHexTargetNotRenderedAsAnchor]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testHexTargetNotRenderedAsAnchor]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInfTargetNotRenderedAsAnchor]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInfTargetNotRenderedAsAnchor]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInvalidTargetNotRenderedAsAnchor]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInvalidTargetNotRenderedAsAnchor]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testPublicAnchorHelpersMatchRendererIds]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testPublicAnchorHelpersMatchRendererIds]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionHasIdAttribute]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionHasIdAttribute]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForDecimalZ]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForDecimalZ]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForNegativeZ]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForNegativeZ]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdPrecedesDataZ]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdPrecedesDataZ]' passed (0.000 seconds). +Test Suite 'CrossPlaneLinkHTMLTests' passed at 2026-10-10 11:55:29.500. + Executed 17 tests, with 0 failures (0 unexpected) in 0.003 (0.004) seconds +Test Suite 'CrossPlaneLinkTests' started at 2026-10-10 11:55:29.500. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testBasicLinkNoText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testBasicLinkNoText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinksFiltersOnlyMissingTargets]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinksFiltersOnlyMissingTargets]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinkTargetExistsFalse]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinkTargetExistsFalse]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDecimalTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDecimalTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDocumentWithNoLinksReturnsEmpty]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDocumentWithNoLinksReturnsEmpty]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testHexTargetIgnored]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testHexTargetIgnored]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphCollapsesRepeatedEdgesInEncounterOrder]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphCollapsesRepeatedEdgesInEncounterOrder]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphKeepsDanglingEdgeStatus]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphKeepsDanglingEdgeStatus]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinksAcrossMultiplePlanesInSourceOrder]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinksAcrossMultiplePlanesInSourceOrder]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithEmptyText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithEmptyText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testMultipleLinksLeftToRight]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testMultipleLinksLeftToRight]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNanTargetIgnored]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNanTargetIgnored]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNegativeDecimalTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNegativeDecimalTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNonDecimalTargetIgnored]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNonDecimalTargetIgnored]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testOrdinaryMarkdownLinkNotExtracted]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testOrdinaryMarkdownLinkNotExtracted]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testScientificNotationTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testScientificNotationTarget]' passed (0.000 seconds). +Test Suite 'CrossPlaneLinkTests' passed at 2026-10-10 11:55:29.504. + Executed 17 tests, with 0 failures (0 unexpected) in 0.003 (0.004) seconds +Test Suite 'DocumentCompositionCodecTests' started at 2026-10-10 11:55:29.504. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCanonicalProfileStoresSharedDefinitionOnceAndIsOrderIndependent]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCanonicalProfileStoresSharedDefinitionOnceAndIsOrderIndependent]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCheckedInGrovePreservesItsSingleCanopyDefinitionAndBindingAcrossFormats]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCheckedInGrovePreservesItsSingleCanopyDefinitionAndBindingAcrossFormats]' passed (0.011 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testJSONAllocationPreflightRejectsExcessiveArraysNestingAndTrailingBytes]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testJSONAllocationPreflightRejectsExcessiveArraysNestingAndTrailingBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileAndDefinitionBytePoliciesBoundBothReaderAndWriter]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileAndDefinitionBytePoliciesBoundBothReaderAndWriter]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileUsesGenericPortableBinaryEnvelopeWithoutAnotherFormat]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileUsesGenericPortableBinaryEnvelopeWithoutAnotherFormat]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateDefinitionIDsAndUnusedMissingReferences]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateDefinitionIDsAndUnusedMissingReferences]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateJSONKeysIncludingEscapedSpelling]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateJSONKeysIncludingEscapedSpelling]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsInvalidUnusedDefinitionsAndDoesNotLoadSourcePaths]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsInvalidUnusedDefinitionsAndDoesNotLoadSourcePaths]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsUnknownManifestEntryAndReferenceKeys]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsUnknownManifestEntryAndReferenceKeys]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRequiresExactEnvelopeAndVersionedManifest]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRequiresExactEnvelopeAndVersionedManifest]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReferenceAttributesPreserveControlsQuotesAndUnicodeWithoutBreakingFences]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReferenceAttributesPreserveControlsQuotesAndUnicodeWithoutBreakingFences]' passed (0.001 seconds). +Test Suite 'DocumentCompositionCodecTests' passed at 2026-10-10 11:55:29.530. + Executed 11 tests, with 0 failures (0 unexpected) in 0.025 (0.026) seconds +Test Suite 'DocumentCompositionTests' started at 2026-10-10 11:55:29.530. +Test Case '-[ThreeMDTests.DocumentCompositionTests testCanceledConstructionAndStorageStayDistinctFromValidationErrors]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testCanceledConstructionAndStorageStayDistinctFromValidationErrors]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testCyclesAreRejectedInRootAndUnusedNodes]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testCyclesAreRejectedInRootAndUnusedNodes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDepthAndReferenceBudgetsHaveExactBoundarySemantics]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDepthAndReferenceBudgetsHaveExactBoundarySemantics]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDocumentPolicyIsIndependentOfCompositionPolicy]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDocumentPolicyIsIndependentOfCompositionPolicy]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testEveryDefinitionIsValidatedEvenWhenUnused]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testEveryDefinitionIsValidatedEvenWhenUnused]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testIDsAreCaseSensitiveAndNeverFileOrNetworkLocations]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testIDsAreCaseSensitiveAndNeverFileOrNetworkLocations]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testMissingRootMissingTargetAndDuplicateDefinitionsAreRejected]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testMissingRootMissingTargetAndDuplicateDefinitionsAreRejected]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testOccurrenceBudgetCountsSharedReferencesWithoutMaterializingThem]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testOccurrenceBudgetCountsSharedReferencesWithoutMaterializingThem]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testReferenceAttributesAreOpaqueUnicodeDataWithCountAndByteLimits]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testReferenceAttributesAreOpaqueUnicodeDataWithCountAndByteLimits]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testResourceLimitsCannotBeRaisedBeyondAbsoluteBounds]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testResourceLimitsCannotBeRaisedBeyondAbsoluteBounds]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testSharedNestedDefinitionsPreserveAxesMetadataAndReferenceOrder]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testSharedNestedDefinitionsPreserveAxesMetadataAndReferenceOrder]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testUniqueSourceByteBudgetCountsEachDefinitionOnce]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testUniqueSourceByteBudgetCountsEachDefinitionOnce]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testUnusedDepthAndOccurrenceBudgetsAreAlsoEnforced]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testUnusedDepthAndOccurrenceBudgetsAreAlsoEnforced]' passed (0.000 seconds). +Test Suite 'DocumentCompositionTests' passed at 2026-10-10 11:55:29.542. + Executed 13 tests, with 0 failures (0 unexpected) in 0.010 (0.011) seconds +Test Suite 'DocumentDiagnosticTests' started at 2026-10-10 11:55:29.542. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancellationIsNeverConvertedIntoAValidationDiagnostic]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancellationIsNeverConvertedIntoAValidationDiagnostic]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancelledCompositionDiagnosticsDoNotBeginPreflightOrGraphValidation]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancelledCompositionDiagnosticsDoNotBeginPreflightOrGraphValidation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticBudgetRejectsBeforeExpensiveGraphSourceValidation]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticBudgetRejectsBeforeExpensiveGraphSourceValidation]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticPreflightStillEnforcesCheapCountPolicies]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticPreflightStillEnforcesCheapCountPolicies]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticsScopeRepeatedInstanceIDsByOwner]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticsScopeRepeatedInstanceIDsByOwner]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticCeilingSignalsUninspectedRemainder]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticCeilingSignalsUninspectedRemainder]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticInputAndValueByteWorkAreBounded]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticInputAndValueByteWorkAreBounded]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testHostileLinkPrefixesDoNotTriggerLegacyRegexDuringDiagnostics]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testHostileLinkPrefixesDoNotTriggerLegacyRegexDuringDiagnostics]' passed (0.016 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSharedDecimalScannerRejectsLongMalformedLinkNumberAndPreservesGrammar]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSharedDecimalScannerRejectsLongMalformedLinkNumberAndPreservesGrammar]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSourceParseDiagnosticsPreserveRealLineEvidence]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSourceParseDiagnosticsPreserveRealLineEvidence]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testValueDiagnosticsHavePlanePathsAndNoInventedLines]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testValueDiagnosticsHavePlanePathsAndNoInventedLines]' passed (0.000 seconds). +Test Suite 'DocumentDiagnosticTests' passed at 2026-10-10 11:55:29.566. + Executed 11 tests, with 0 failures (0 unexpected) in 0.024 (0.025) seconds +Test Suite 'DocumentEditingTests' started at 2026-10-10 11:55:29.566. +Test Case '-[ThreeMDTests.DocumentEditingTests testAtomicCoordinateSwapRetainsIDsSourceOrderMetadataAndLegacyLinks]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testAtomicCoordinateSwapRetainsIDsSourceOrderMetadataAndLegacyLinks]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testCancelledTransactionPropagatesCancellation]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testCancelledTransactionPropagatesCancellation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testCanonicalReopenHasSameRevisionAndCodableValuesRoundTrip]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testCanonicalReopenHasSameRevisionAndCodableValuesRoundTrip]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testFailureAfterValidFirstOperationPublishesNothing]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testFailureAfterValidFirstOperationPublishesNothing]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testFinalCoordinateConflictReturnsPrecisePathAndNoMutation]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testFinalCoordinateConflictReturnsPrecisePathAndNoMutation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testInsertMoveRemoveAndHeaderTransactionPreservesUnrelatedPlanes]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testInsertMoveRemoveAndHeaderTransactionPreservesUnrelatedPlanes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidFinalDirectValuesCannotEscapeStorageValidation]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidFinalDirectValuesCannotEscapeStorageValidation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidInsertMoveAndDuplicateIdentityAreDiagnosed]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidInsertMoveAndDuplicateIdentityAreDiagnosed]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testNoIdentityLegacyDocumentRequiresExplicitAdoptionForTargetedEdits]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testNoIdentityLegacyDocumentRequiresExplicitAdoptionForTargetedEdits]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testOperationOperandAndExpectedRevisionBudgetsAreEnforced]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testOperationOperandAndExpectedRevisionBudgetsAreEnforced]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testReplacementCannotSilentlyChangeOrDropIdentity]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testReplacementCannotSilentlyChangeOrDropIdentity]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testSnapshotDecoderRejectsForgedRevision]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testSnapshotDecoderRejectsForgedRevision]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testStaleExactRevisionRejectsChangedContentAndUnicodeEquivalentBytes]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testStaleExactRevisionRejectsChangedContentAndUnicodeEquivalentBytes]' passed (0.001 seconds). +Test Suite 'DocumentEditingTests' passed at 2026-10-10 11:55:29.576. + Executed 13 tests, with 0 failures (0 unexpected) in 0.008 (0.009) seconds +Test Suite 'DocumentFileCompositionTests' started at 2026-10-10 11:55:29.576. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testAttributeBoundCountsNormalizedDirectoryPrefixBytes]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testAttributeBoundCountsNormalizedDirectoryPrefixBytes]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testBundledTextAndBinaryReopenWithoutSupplyingAnySourceFiles]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testBundledTextAndBinaryReopenWithoutSupplyingAnySourceFiles]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCachedSubtreeIsChargedAtItsDeeperOccurrenceAgainstTheDiscoveryCeiling]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCachedSubtreeIsChargedAtItsDeeperOccurrenceAgainstTheDiscoveryCeiling]' passed (0.259 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationDuringARunningFanOutResolutionPublishesNoResult]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationDuringARunningFanOutResolutionPublishesNoResult]' passed (1.146 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationStaysDistinctAndNeverReturnsPartialComposition]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationStaysDistinctAndNeverReturnsPartialComposition]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancelledPathResolutionPrecedesOversizedInput]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancelledPathResolutionPrecedesOversizedInput]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testChildStorageFailuresKeepOriginalErrorType]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testChildStorageFailuresKeepOriginalErrorType]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDisconnectedEmbeddedLedgerUsesActualEntryDepthAndRepeatedCachedFiles]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDisconnectedEmbeddedLedgerUsesActualEntryDepthAndRepeatedCachedFiles]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDiscoveryMissingFilePrecedesUnvalidatedFinalGraphDepth]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDiscoveryMissingFilePrecedesUnvalidatedFinalGraphDepth]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateBasenamesAndUnicodeScalarOrderingRemainDistinct]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateBasenamesAndUnicodeScalarOrderingRemainDistinct]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateNormalizedAndCanonicallyEquivalentSourcesFailBeforeDecode]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateNormalizedAndCanonicallyEquivalentSourcesFailBeforeDecode]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingBundleRetainsUnusedEntriesOpaqueAttributesAndIdentitiesAndScansEveryLedger]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingBundleRetainsUnusedEntriesOpaqueAttributesAndIdentitiesAndScansEveryLedger]' passed (0.009 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingEdgesPrecedeLedgerEdgesAndEmbeddedLedgersResolveFromTheirBundleFolder]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingEdgesPrecedeLedgerEdgesAndEmbeddedLedgersResolveFromTheirBundleFolder]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFileCyclesIncludeUnusedEmbeddedEntryLedgers]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFileCyclesIncludeUnusedEmbeddedEntryLedgers]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFixedFileDiscoverySafetyCeilingRemainsBoundedForDisconnectedEntries]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFixedFileDiscoverySafetyCeilingRemainsBoundedForDisconnectedEntries]' passed (0.211 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerEscapesDecodeBeforePathGrammar]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerEscapesDecodeBeforePathGrammar]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerRejectsDuplicateEscapedKeysAndMalformedValuesAndGlyphs]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerRejectsDuplicateEscapedKeysAndMalformedValuesAndGlyphs]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongDirectoryOwnersResolveRepeatedSourcesOnceAndRefuseOverBoundTargetsAtTheFirstEdge]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongDirectoryOwnersResolveRepeatedSourcesOnceAndRefuseOverBoundTargetsAtTheFirstEdge]' passed (1.624 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongOwnerPathWithManyReferencesResolvesEveryReferenceInItsDirectory]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongOwnerPathWithManyReferencesResolvesEveryReferenceInItsDirectory]' passed (0.109 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredDefinitionDepthReferenceTraversalAndAttributePoliciesApplyToCompleteGraph]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredDefinitionDepthReferenceTraversalAndAttributePoliciesApplyToCompleteGraph]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredPolicyChargesOriginalPathBytesBeforePathGrammarAndEncodedBytesBeforeDecoding]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredPolicyChargesOriginalPathBytesBeforePathGrammarAndEncodedBytesBeforeDecoding]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testMissingRootAndLinkedChildReportNormalizedMissingPaths]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testMissingRootAndLinkedChildReportNormalizedMissingPaths]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedParentPathsAndRefreshedChildrenRetainDeterministicIDs]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedParentPathsAndRefreshedChildrenRetainDeterministicIDs]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedProfileUsesProfileRecordPolicyWhileOrdinaryAndChildDocumentsKeepTheirOwnPolicy]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedProfileUsesProfileRecordPolicyWhileOrdinaryAndChildDocumentsKeepTheirOwnPolicy]' passed (0.006 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOnlyReachableSourcesDecode]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOnlyReachableSourcesDecode]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOuterRecognitionDoesNotUseCallerPlaneLimitBeforeByteAndLinePolicies]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOuterRecognitionDoesNotUseCallerPlaneLimitBeforeByteAndLinePolicies]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOverBoundLedgerEdgeIsRefusedWhileResolvingBeforeLaterRefusals]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOverBoundLedgerEdgeIsRefusedWhileResolvingBeforeLaterRefusals]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOwnerDirectoryResolutionKeepsParentDotAndGrammarSemantics]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOwnerDirectoryResolutionKeepsParentDotAndGrammarSemantics]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testPathsNormalizeNFCAndParentsWithoutPercentDecoding]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testPathsNormalizeNFCAndParentsWithoutPercentDecoding]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testReachableEncodedByteAndSuppliedCountAndAggregatePathLimitsFailBeforeIndexingOrPublishing]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testReachableEncodedByteAndSuppliedCountAndAggregatePathLimitsFailBeforeIndexingOrPublishing]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRefusalsFollowEntryIDThenGlyphDiscoveryOrder]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRefusalsFollowEntryIDThenGlyphDiscoveryOrder]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRepeatedCachedFilesAreStillCheckedAgainstFinalCompleteEntryDepth]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRepeatedCachedFilesAreStillCheckedAgainstFinalCompleteEntryDepth]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testResolverOutputRebundlesWithOpaqueGlyphAndSourceFileAttributes]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testResolverOutputRebundlesWithOpaqueGlyphAndSourceFileAttributes]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRootAndUnreachableSuppliedPathsUseTheLedgerPathGrammar]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRootAndUnreachableSuppliedPathsUseTheLedgerPathGrammar]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSelfAndAliasCyclesCompareNormalizedPaths]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSelfAndAliasCyclesCompareNormalizedPaths]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSimpleRepeatedFilesProduceOneDefinitionAndPreserveOrdinaryDocumentFields]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSimpleRepeatedFilesProduceOneDefinitionAndPreserveOrdinaryDocumentFields]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSourceFileAttributeBoundCountsNormalizedUTF8Bytes]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSourceFileAttributeBoundCountsNormalizedUTF8Bytes]' passed (0.150 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testStandalonePathsAndLedgersPastTheOldRecordSizeAreSaved]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testStandalonePathsAndLedgersPastTheOldRecordSizeAreSaved]' passed (0.973 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testTextAndUncompressedBinaryChildrenBundleIdenticallyWithoutExtensionRestrictions]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testTextAndUncompressedBinaryChildrenBundleIdenticallyWithoutExtensionRestrictions]' passed (0.004 seconds). +Test Suite 'DocumentFileCompositionTests' passed at 2026-10-10 11:55:34.129. + Executed 39 tests, with 0 failures (0 unexpected) in 4.550 (4.553) seconds +Test Suite 'DocumentIdentityTests' started at 2026-10-10 11:55:34.129. +Test Case '-[ThreeMDTests.DocumentIdentityTests testAdoptionPreservesNamespaceMetadataAndDeterministicallySkipsExistingIDs]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testAdoptionPreservesNamespaceMetadataAndDeterministicallySkipsExistingIDs]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testCancelledIdentityAdoptionReturnsCancellation]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testCancelledIdentityAdoptionReturnsCancellation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicateReferenceIdentityFailsWithinOwnerOnly]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicateReferenceIdentityFailsWithinOwnerOnly]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicatesAreRejectedRatherThanSilentlyRegenerated]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicatesAreRejectedRatherThanSilentlyRegenerated]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testExplicitIdentitiesRoundTripThroughTextAndBothBinaryBackends]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testExplicitIdentitiesRoundTripThroughTextAndBothBinaryBackends]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testIdentityAdoptionRespectsDocumentAndReferenceAttributeBudgets]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testIdentityAdoptionRespectsDocumentAndReferenceAttributeBudgets]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testRepeatedTargetsGainIndependentOwnerScopedReferenceIDs]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testRepeatedTargetsGainIndependentOwnerScopedReferenceIDs]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testUnsafeAndEmptyExistingIDsAreRejectedWithExactPaths]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testUnsafeAndEmptyExistingIDsAreRejectedWithExactPaths]' passed (0.001 seconds). +Test Suite 'DocumentIdentityTests' passed at 2026-10-10 11:55:34.136. + Executed 8 tests, with 0 failures (0 unexpected) in 0.007 (0.008) seconds +Test Suite 'DocumentStorageBoundsTests' started at 2026-10-10 11:55:34.136. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testADocumentPastTheOldCeilingRoundTrips]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testADocumentPastTheOldCeilingRoundTrips]' passed (18.970 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCanceledTasksCannotReturnPartiallyEncodedOrDecodedDocuments]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCanceledTasksCannotReturnPartiallyEncodedOrDecodedDocuments]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCombinedScalarAndDirectiveBytesCannotBypassTheOutputBound]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCombinedScalarAndDirectiveBytesCannotBypassTheOutputBound]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testLimitsArePositiveAndHaveNoAbsoluteCeiling]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testLimitsArePositiveAndHaveNoAbsoluteCeiling]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPhysicalLinesAreBoundedBeforeParsingEvenForBlankInputs]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPhysicalLinesAreBoundedBeforeParsingEvenForBlankInputs]' passed (0.008 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPlanePreflightIgnoresDirectivesInsideBothKindsOfFences]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPlanePreflightIgnoresDirectivesInsideBothKindsOfFences]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testRecordBoundIncludesWholePlaneBodiesAndEscapedScalarLines]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testRecordBoundIncludesWholePlaneBodiesAndEscapedScalarLines]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testTextAndPortableBinaryAcceptExactByteBounds]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testTextAndPortableBinaryAcceptExactByteBounds]' passed (0.001 seconds). +Test Suite 'DocumentStorageBoundsTests' passed at 2026-10-10 11:55:53.119. + Executed 8 tests, with 0 failures (0 unexpected) in 18.982 (18.982) seconds +Test Suite 'DocumentStorageCompressionTests' started at 2026-10-10 11:55:53.119. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testAppleLZFSECompressionIsDeterministicAndRoundTripsGeneralText]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testAppleLZFSECompressionIsDeterministicAndRoundTripsGeneralText]' passed (0.143 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testCanceledCompressionAndDecompressionRemainCancellationErrors]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testCanceledCompressionAndDecompressionRemainCancellationErrors]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testDeclaredOutputSizeCannotTruncateOrGrowDecompression]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testDeclaredOutputSizeCannotTruncateOrGrowDecompression]' passed (0.029 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testEveryTruncationAndMalformedCompressionPayloadFailsWithoutPartialResults]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testEveryTruncationAndMalformedCompressionPayloadFailsWithoutPartialResults]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLargeFirstStreamDrainsMultipleChunksBeforeFinalMarkerAndRejectsConcatenation]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLargeFirstStreamDrainsMultipleChunksBeforeFinalMarkerAndRejectsConcatenation]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLZFSERejectsTrailingAndConcatenatedStreamsWithValidChecksums]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLZFSERejectsTrailingAndConcatenatedStreamsWithValidChecksums]' passed (0.000 seconds). +Test Suite 'DocumentStorageCompressionTests' passed at 2026-10-10 11:55:53.300. + Executed 6 tests, with 0 failures (0 unexpected) in 0.181 (0.181) seconds +Test Suite 'DocumentStorageDecimalTests' started at 2026-10-10 11:55:53.300. +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testCancellationDuringAnInvalidParseRemainsCancellationError]' started. +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testCancellationDuringAnInvalidParseRemainsCancellationError]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testLongMalformedDecimalRejectsReadableAndChecksummedBinaryWithoutBacktracking]' started. +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testLongMalformedDecimalRejectsReadableAndChecksummedBinaryWithoutBacktracking]' passed (0.002 seconds). +Test Suite 'DocumentStorageDecimalTests' passed at 2026-10-10 11:55:53.303. + Executed 2 tests, with 0 failures (0 unexpected) in 0.003 (0.003) seconds +Test Suite 'DocumentStorageStructuredTests' started at 2026-10-10 11:55:53.303. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testAmplifiedQuotedKeysAreRejectedByPhaseLBeforeAnyPhaseQParse]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testAmplifiedQuotedKeysAreRejectedByPhaseLBeforeAnyPhaseQParse]' passed (0.398 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanceledTasksReturnNoStructuredDocumentOrBytes]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanceledTasksReturnNoStructuredDocumentOrBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCancellationIsCheckedAtEveryStructuredCheckpoint]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCancellationIsCheckedAtEveryStructuredCheckpoint]' passed (0.944 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanonicallyEquivalentKeysInOnePayloadMapAreInvalidDocuments]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanonicallyEquivalentKeysInOnePayloadMapAreInvalidDocuments]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChecksumSlicingMatchesTheBytewiseDefinitionAtEveryAlignment]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChecksumSlicingMatchesTheBytewiseDefinitionAtEveryAlignment]' passed (1.697 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChunkedUTF8ValidationAgreesWithWholeValidationAcrossChunkBoundaries]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChunkedUTF8ValidationAgreesWithWholeValidationAcrossChunkBoundaries]' passed (0.473 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testConcurrentTasksEncodeAndDecodeIndependently]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testConcurrentTasksEncodeAndDecodeIndependently]' passed (0.020 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testContainerInfoReportsRawHeaderFieldsWithoutValidation]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testContainerInfoReportsRawHeaderFieldsWithoutValidation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCountFramingDividesAndPrecedesThePlaneLimitAtTheLargestCounts]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCountFramingDividesAndPrecedesThePlaneLimitAtTheLargestCounts]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodeAcceptsDataSlicesWithANonzeroStartIndex]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodeAcceptsDataSlicesWithANonzeroStartIndex]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodedLengthBoundPrecedesTheChecksumAndDecompression]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodedLengthBoundPrecedesTheChecksumAndDecompression]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodingPeakMemoryGrowthStaysUnderThreeTimesTheInput]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodingPeakMemoryGrowthStaysUnderThreeTimesTheInput]' passed (30.487 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEightyEmptyPlanesDecodeUnderAnEncodedLimitTheirTextWouldExceed]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEightyEmptyPlanesDecodeUnderAnEncodedLimitTheirTextWouldExceed]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryGoldenIsByteIdenticalAndDecodesToTheBoundedTextDecode]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryGoldenIsByteIdenticalAndDecodesToTheBoundedTextDecode]' passed (0.076 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryVectorReportsItsCodeUnderItsLimits]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryVectorReportsItsCodeUnderItsLimits]' passed (0.020 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testFrozenWhitespaceSetHoldsExactlyNineteenScalars]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testFrozenWhitespaceSetHoldsExactlyNineteenScalars]' passed (0.270 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testKeysAreOrderedByUTF8BytesWhichIsCodePointOrder]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testKeysAreOrderedByUTF8BytesWhichIsCodePointOrder]' passed (0.007 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLongAttributeKeysAreComparedWithTheirLowercaseAcrossChunkEdges]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLongAttributeKeysAreComparedWithTheirLowercaseAcrossChunkEdges]' passed (0.241 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredPayloadsRoundTripAndKeepTheDecodedBound]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredPayloadsRoundTripAndKeepTheDecodedBound]' passed (0.006 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredStreamsMustEndOnceAndMatchTheDeclaredLength]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredStreamsMustEndOnceAndMatchTheDeclaredLength]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtEveryExampleLimitEdge]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtEveryExampleLimitEdge]' passed (1.261 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtTheLimitEdgesOfGeneratedDocuments]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtTheLimitEdgesOfGeneratedDocuments]' passed (10.356 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMutatedFilesGiveOneTypedOutcomeAndAcceptedOnesAreCanonical]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMutatedFilesGiveOneTypedOutcomeAndAcceptedOnesAreCanonical]' passed (3.331 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumberFormsFollowTheCanonicalTableAndDecodeBitExactly]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumberFormsFollowTheCanonicalTableAndDecodeBitExactly]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumericPowersSpellAsTheSharedCanonicalNumbersAndRoundTripBitExactly]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumericPowersSpellAsTheSharedCanonicalNumbersAndRoundTripBitExactly]' passed (0.183 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testRandomBitPatternsTakeTheirCanonicalFormAndRoundTripBitExactly]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testRandomBitPatternsTakeTheirCanonicalFormAndRoundTripBitExactly]' passed (2.330 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesAgreeWithTheTextParserOnRandomBodies]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesAgreeWithTheTextParserOnRandomBodies]' passed (7.871 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesMatchTheTextRoundTripOnHandCases]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesMatchTheTextRoundTripOnHandCases]' passed (0.008 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testShortStringsChargeTheCancellationBudgetInEveryPass]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testShortStringsChargeTheCancellationBudgetInEveryPass]' passed (1.817 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSizeGateHoldsForEveryExampleAndTheCorpus]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSizeGateHoldsForEveryExampleAndTheCorpus]' passed (0.653 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testTextContainerWriterKeepsTheTwoZeroBytesAndHeaderChecks]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testTextContainerWriterKeepsTheTwoZeroBytesAndHeaderChecks]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUnicodeSkewVectorsFollowTheRuntimeUnicodeData]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUnicodeSkewVectorsFollowTheRuntimeUnicodeData]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUTF8ValidityIsRepairedDecodingThatEqualsTheInputBytes]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUTF8ValidityIsRepairedDecodingThatEqualsTheInputBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testVarEncodesMinimallyAndDecodesEveryBoundary]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testVarEncodesMinimallyAndDecodesEveryBoundary]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWorkedExamplesHoldTheBytesAndChecksumsOfTheSpecification]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWorkedExamplesHoldTheBytesAndChecksumsOfTheSpecification]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterAcceptanceEqualsValidationAndDecodeEqualsTheTextDecode]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterAcceptanceEqualsValidationAndDecodeEqualsTheTextDecode]' passed (3.372 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterCapsTheUncompressedContainerAtTheEncodedLimit]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterCapsTheUncompressedContainerAtTheEncodedLimit]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterOutputDecodesUnderTheSameLimitsToTheNormalizedDocument]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterOutputDecodesUnderTheSameLimitsToTheNormalizedDocument]' passed (0.436 seconds). +Test Suite 'DocumentStorageStructuredTests' passed at 2026-10-10 11:56:59.577. + Executed 38 tests, with 0 failures (0 unexpected) in 66.270 (66.274) seconds +Test Suite 'DocumentStorageTests' started at 2026-10-10 11:56:59.577. +Test Case '-[ThreeMDTests.DocumentStorageTests testAllHeaderFieldsAndCorruptionAreChecked]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testAllHeaderFieldsAndCorruptionAreChecked]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testBinaryDecodeHandlesDataSlices]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testBinaryDecodeHandlesDataSlices]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInCompressedCanopyRoundTripsToItsReadableDocument]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInCompressedCanopyRoundTripsToItsReadableDocument]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInExtensionManifestDescribesTheActualSixArtifacts]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInExtensionManifestDescribesTheActualSixArtifacts]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInPortableCanopyRoundTripsToItsReadableDocument]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInPortableCanopyRoundTripsToItsReadableDocument]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testContainerPayloadMustBeValidUTF8AndThreeMDText]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testContainerPayloadMustBeValidUTF8AndThreeMDText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testDirectDocumentValidationRejectsLossyOrAmbiguousSerialization]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testDirectDocumentValidationRejectsLossyOrAmbiguousSerialization]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testGeneralDocumentsPreserveUnicodeCustomAxesAndFractionalPositions]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testGeneralDocumentsPreserveUnicodeCustomAxesAndFractionalPositions]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testPortableContainerFixedVector]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testPortableContainerFixedVector]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testStorageRetainsTextGrammarAndLegacySerializerPreservesLiteralQuotes]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testStorageRetainsTextGrammarAndLegacySerializerPreservesLiteralQuotes]' passed (0.000 seconds). +Test Suite 'DocumentStorageTests' passed at 2026-10-10 11:56:59.587. + Executed 10 tests, with 0 failures (0 unexpected) in 0.009 (0.010) seconds +Test Suite 'ExtensionConformanceTests' started at 2026-10-10 11:56:59.587. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testCanonicalNumericBitPatternsMatchSharedSwiftFormattingVectors]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testCanonicalNumericBitPatternsMatchSharedSwiftFormattingVectors]' passed (0.007 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testDocumentEnvelopeAndProfileGoldensMatchExactCanonicalBytes]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testDocumentEnvelopeAndProfileGoldensMatchExactCanonicalBytes]' passed (0.011 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedBinaryChecksumGoldensRejectCorruption]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedBinaryChecksumGoldensRejectCorruption]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedCompositionTransactionsKeepUnchangedDefinitionsAndRepeatedInstances]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedCompositionTransactionsKeepUnchangedDefinitionsAndRepeatedInstances]' passed (0.011 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedDocumentTransactionsValidateFinalValuesAtomically]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedDocumentTransactionsValidateFinalValuesAtomically]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedFailedTransactionsHaveStableCodesPathsAndNoPartialPublication]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedFailedTransactionsHaveStableCodesPathsAndNoPartialPublication]' passed (0.008 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedIdentityAdoptionPreservesOpaqueFieldsAndOwnerScopes]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedIdentityAdoptionPreservesOpaqueFieldsAndOwnerScopes]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testStrictCompositionJSONRejectsCanonicallyEquivalentDuplicateKeys]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testStrictCompositionJSONRejectsCanonicallyEquivalentDuplicateKeys]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeKeyOrderingGoldensPreserveOriginalSpellingAndExactBytes]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeKeyOrderingGoldensPreserveOriginalSpellingAndExactBytes]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeSourceKeyCollisionsKeepFirstSpellingAndLastValue]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeSourceKeyCollisionsKeepFirstSpellingAndLastValue]' passed (0.001 seconds). +Test Suite 'ExtensionConformanceTests' passed at 2026-10-10 11:56:59.638. + Executed 10 tests, with 0 failures (0 unexpected) in 0.050 (0.051) seconds +Test Suite 'HTMLRendererTests' started at 2026-10-10 11:56:59.638. +Test Case '-[ThreeMDTests.HTMLRendererTests testAmpersandEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testAmpersandEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testAxisEmittedInMeta]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testAxisEmittedInMeta]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testBodyRenderedAsMarkdown]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testBodyRenderedAsMarkdown]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testDecimalZInDataAttribute]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testDecimalZInDataAttribute]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testDoubleQuoteEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testDoubleQuoteEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelRenderedAsHeading]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelRenderedAsHeading]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelSpecialCharsEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelSpecialCharsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testLessThanEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testLessThanEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testMissingTitleFallsBackToDefault]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testMissingTitleFallsBackToDefault]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputContainsHeadAndBody]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputContainsHeadAndBody]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputIsStandaloneHTML]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputIsStandaloneHTML]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testPlaneCountMatchesSections]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testPlaneCountMatchesSections]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testPreambleRenderedInSection]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testPreambleRenderedInSection]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesAriaLabel]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesAriaLabel]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesDataZ]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesDataZ]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testSingleQuoteEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testSingleQuoteEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInH1]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInH1]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInTitleElement]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInTitleElement]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleSpecialCharsEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleSpecialCharsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testVersionEmittedInMeta]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testVersionEmittedInMeta]' passed (0.000 seconds). +Test Suite 'HTMLRendererTests' passed at 2026-10-10 11:56:59.643. + Executed 20 tests, with 0 failures (0 unexpected) in 0.004 (0.005) seconds +Test Suite 'InterchangeConformanceTests' started at 2026-10-10 11:56:59.643. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testAdoptionAndDeterministicDocumentEditsHaveExactRevisionAndRejectReuse]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testAdoptionAndDeterministicDocumentEditsHaveExactRevisionAndRejectReuse]' passed (0.051 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testASCIIFencePrefixesWithCombiningMarksKeepInnerDirectivesAsBody]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testASCIIFencePrefixesWithCombiningMarksKeepInnerDirectivesAsBody]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogIncludesEveryDeclaredExtensionSourceAndBinaryGolden]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogIncludesEveryDeclaredExtensionSourceAndBinaryGolden]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogRequiresEveryLegacySourceAndHasUniqueCompleteCases]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogRequiresEveryLegacySourceAndHasUniqueCompleteCases]' passed (0.020 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCombiningMarkEscapesChargeExactCanonicalUTF8OutputBytes]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCombiningMarkEscapesChargeExactCanonicalUTF8OutputBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryInvalidCatalogSourceReportsItsRequiredTypedError]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryInvalidCatalogSourceReportsItsRequiredTypedError]' passed (0.007 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryValidCatalogSourceAndLegacyOutputPreserveExactCanonicalBytes]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryValidCatalogSourceAndLegacyOutputPreserveExactCanonicalBytes]' passed (0.057 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testLegacySerializerPreservesRepresentableScalarQuotesAndFoundationEdgeWhitespace]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testLegacySerializerPreservesRepresentableScalarQuotesAndFoundationEdgeWhitespace]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarFieldSeparatorsAndSpaceTokensMatchBoundedPreflight]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarFieldSeparatorsAndSpaceTokensMatchBoundedPreflight]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarQuoteAndEscapeDelimitersPreserveAdjacentCombiningMarks]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarQuoteAndEscapeDelimitersPreserveAdjacentCombiningMarks]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testSharedDAGAndUnusedDefinitionsSurviveAdoptionAndRootReplacement]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testSharedDAGAndUnusedDefinitionsSurviveAdoptionAndRootReplacement]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testStorageRejectsReservedASCIIDelimitersInsideCombiningGraphemes]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testStorageRejectsReservedASCIIDelimitersInsideCombiningGraphemes]' passed (0.000 seconds). +Test Suite 'InterchangeConformanceTests' passed at 2026-10-10 11:56:59.793. + Executed 12 tests, with 0 failures (0 unexpected) in 0.149 (0.150) seconds +Test Suite 'MarkdownRendererTests' started at 2026-10-10 11:56:59.793. +Test Case '-[ThreeMDTests.MarkdownRendererTests testAmpersandInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testAmpersandInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlankLineSeparatesParagraphs]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlankLineSeparatesParagraphs]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlockquote]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlockquote]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleAsterisk]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleAsterisk]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleUnderscore]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleUnderscore]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldMidSentence]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldMidSentence]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemLowercase]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemLowercase]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemUppercase]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemUppercase]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testDoubleQuoteInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testDoubleQuoteInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlock]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlock]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockEscapesHTML]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockEscapesHTML]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockPreservesMarkdownLookingContent]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockPreservesMarkdownLookingContent]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockWithLanguage]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockWithLanguage]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH1]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH1]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH2]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH2]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH3]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH3]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH4]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH4]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH5]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH5]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH6]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH6]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingFollowedByParagraph]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingFollowedByParagraph]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingRequiresSpaceAfterHash]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingRequiresSpaceAfterHash]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCode]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCode]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeDoesNotRenderMarkdown]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeDoesNotRenderMarkdown]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeEscapesHTML]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeEscapesHTML]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicAsterisk]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicAsterisk]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicUnderscore]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicUnderscore]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLessThanInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLessThanInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLink]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLink]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkHrefIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkHrefIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkTextIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkTextIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineBlockquote]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineBlockquote]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineParagraphJoinsWithSpace]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineParagraphJoinsWithSpace]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testOrderedList]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testOrderedList]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testParagraphWithBoldAndLink]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testParagraphWithBoldAndLink]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleLineParagraph]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleLineParagraph]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleQuoteInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleQuoteInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testUncheckedTaskItem]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testUncheckedTaskItem]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListAsterisk]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListAsterisk]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListDash]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListDash]' passed (0.000 seconds). +Test Suite 'MarkdownRendererTests' passed at 2026-10-10 11:56:59.801. + Executed 39 tests, with 0 failures (0 unexpected) in 0.005 (0.008) seconds +Test Suite 'ParseErrorMetadataTests' started at 2026-10-10 11:56:59.801. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testDuplicatePlaneMetadata]' started. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testDuplicatePlaneMetadata]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testInvalidDirectiveMetadata]' started. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testInvalidDirectiveMetadata]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testMissingVersionCode]' started. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testMissingVersionCode]' passed (0.000 seconds). +Test Suite 'ParseErrorMetadataTests' passed at 2026-10-10 11:56:59.801. + Executed 3 tests, with 0 failures (0 unexpected) in 0.000 (0.001) seconds +Test Suite 'ParserNumericTests' started at 2026-10-10 11:56:59.801. +Test Case '-[ThreeMDTests.ParserNumericTests testFiniteDecimalGrammarIsPreservedForEveryCoordinate]' started. +Test Case '-[ThreeMDTests.ParserNumericTests testFiniteDecimalGrammarIsPreservedForEveryCoordinate]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.ParserNumericTests testMalformedAndNonfiniteNumbersAreRejectedForEveryCoordinate]' started. +Test Case '-[ThreeMDTests.ParserNumericTests testMalformedAndNonfiniteNumbersAreRejectedForEveryCoordinate]' passed (0.002 seconds). +Test Suite 'ParserNumericTests' passed at 2026-10-10 11:56:59.804. + Executed 2 tests, with 0 failures (0 unexpected) in 0.002 (0.003) seconds +Test Suite 'ParserTests' started at 2026-10-10 11:56:59.804. +Test Case '-[ThreeMDTests.ParserTests testAxisDefaultsToLayer]' started. +Test Case '-[ThreeMDTests.ParserTests testAxisDefaultsToLayer]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testAxisRawValueNormalized]' started. +Test Case '-[ThreeMDTests.ParserTests testAxisRawValueNormalized]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.ParserTests testDecimalZValue]' started. +Test Case '-[ThreeMDTests.ParserTests testDecimalZValue]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testDuplicatePositionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testDuplicatePositionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testEmptyDocumentProducesNoPlanes]' started. +Test Case '-[ThreeMDTests.ParserTests testEmptyDocumentProducesNoPlanes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testFrontmatterIgnoresCommentLines]' started. +Test Case '-[ThreeMDTests.ParserTests testFrontmatterIgnoresCommentLines]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testFrontmatterStripsQuotedValues]' started. +Test Case '-[ThreeMDTests.ParserTests testFrontmatterStripsQuotedValues]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testInvalidDirectiveTokenThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testInvalidDirectiveTokenThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testKnownAxesMatchSpec]' started. +Test Case '-[ThreeMDTests.ParserTests testKnownAxesMatchSpec]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testLeadingBlankLinesBeforeFrontmatter]' started. +Test Case '-[ThreeMDTests.ParserTests testLeadingBlankLinesBeforeFrontmatter]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testMissingFrontmatterThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testMissingFrontmatterThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testMissingPlanePositionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testMissingPlanePositionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testMissingVersionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testMissingVersionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNegativeZValue]' started. +Test Case '-[ThreeMDTests.ParserTests testNegativeZValue]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNonNumericPositionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testNonNumericPositionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNonNumericXThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testNonNumericXThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNonNumericYThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testNonNumericYThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParseErrorDescriptions]' started. +Test Case '-[ThreeMDTests.ParserTests testParseErrorDescriptions]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParsesFrontmatter]' started. +Test Case '-[ThreeMDTests.ParserTests testParsesFrontmatter]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParsesMultiplePlanes]' started. +Test Case '-[ThreeMDTests.ParserTests testParsesMultiplePlanes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParsesPlaneCoordinatesAndAttributes]' started. +Test Case '-[ThreeMDTests.ParserTests testParsesPlaneCoordinatesAndAttributes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlainMarkdownBecomesSinglePlane]' started. +Test Case '-[ThreeMDTests.ParserTests testPlainMarkdownBecomesSinglePlane]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlaneAtZReturnsNilForMissingPosition]' started. +Test Case '-[ThreeMDTests.ParserTests testPlaneAtZReturnsNilForMissingPosition]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlaneBodyTrimsLeadingAndTrailingBlanks]' started. +Test Case '-[ThreeMDTests.ParserTests testPlaneBodyTrimsLeadingAndTrailingBlanks]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlanesByZAreSorted]' started. +Test Case '-[ThreeMDTests.ParserTests testPlanesByZAreSorted]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPreambleBeforeFirstPlane]' started. +Test Case '-[ThreeMDTests.ParserTests testPreambleBeforeFirstPlane]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testReservedAttributeKeysNotInExtras]' started. +Test Case '-[ThreeMDTests.ParserTests testReservedAttributeKeysNotInExtras]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testRoundTripThroughSerializer]' started. +Test Case '-[ThreeMDTests.ParserTests testRoundTripThroughSerializer]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithMetadataAndAttributes]' started. +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithMetadataAndAttributes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithPreamble]' started. +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithPreamble]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testUnclosedFrontmatterThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testUnclosedFrontmatterThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testWindowsLineEndingsNormalized]' started. +Test Case '-[ThreeMDTests.ParserTests testWindowsLineEndingsNormalized]' passed (0.000 seconds). +Test Suite 'ParserTests' passed at 2026-10-10 11:56:59.811. + Executed 32 tests, with 0 failures (0 unexpected) in 0.005 (0.007) seconds +Test Suite '3mdPackageTests.xctest' passed at 2026-10-10 11:56:59.811. + Executed 322 tests, with 0 failures (0 unexpected) in 90.338 (90.361) seconds +Test Suite 'All tests' passed at 2026-10-10 11:56:59.811. + Executed 322 tests, with 0 failures (0 unexpected) in 90.338 (90.363) seconds +◇ Test run started. +↳ Testing Library Version: 1902 +↳ Target Platform: arm64e-apple-macos14.0 +✔ Test run with 0 tests in 0 suites passed after 0.001 seconds. + ✔ Step 3 done (1m 31.210s) + ▶️ Running task: js +bun install v1.4.0 (34cbb9a40) + +Checked 5 installs across 6 packages (no changes) [22.00ms] +$ tsc --noEmit +$ bun build ./src/index.ts --outdir ./dist --target node --format esm && tsc -p tsconfig.build.json +Bundled 9 modules in 16ms + + index.js 146.91 KB (entry point) + +bun test v1.4.0 (34cbb9a40) + +test/interchange.test.ts: +(pass) lossless cross-language interchange > raw parsing and bounded decoding use the literal Foundation whitespace set [20.73ms] +(pass) lossless cross-language interchange > Unicode whitespace fences do not invent directives during bounded preflight [1.95ms] +(pass) lossless cross-language interchange > UTF-8 decoding leaves BOM removal to the parser exactly once [0.26ms] +(pass) lossless cross-language interchange > source dictionary collisions retain first spelling and the last assignment in source order [8.95ms] +(pass) lossless cross-language interchange > legacy serialization preserves literal apostrophes, edge whitespace, quotes and backslashes [1.50ms] +(pass) lossless cross-language interchange > legacy number formatting and Unicode scalar key order agree with canonical wire writers [1.10ms] +(pass) lossless cross-language interchange > links preserve long finite targets, long labels and multiline labels [0.39ms] +(pass) lossless cross-language interchange > linear link scanning preserves reference regex matching for malformed nested candidates [2.32ms] + +test/structured.test.ts: +(pass) structured goldens (test-plan section 1) > the manifest lists 49 interchange anchors, 2 examples and 3 worked examples [0.08ms] +(pass) structured goldens (test-plan section 1) > axis-48: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [4.80ms] +(pass) structured goldens (test-plan section 1) > axis-49: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.69ms] +(pass) structured goldens (test-plan section 1) > axis-50: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.44ms] +(pass) structured goldens (test-plan section 1) > axis-51: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.47ms] +(pass) structured goldens (test-plan section 1) > axis-52: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.64ms] +(pass) structured goldens (test-plan section 1) > axis-53: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.40ms] +(pass) structured goldens (test-plan section 1) > axis-54: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.64ms] +(pass) structured goldens (test-plan section 1) > axis-55: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.56ms] +(pass) structured goldens (test-plan section 1) > axis-56: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.40ms] +(pass) structured goldens (test-plan section 1) > axis-57: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.55ms] +(pass) structured goldens (test-plan section 1) > combining-mark-delimiters: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [1.63ms] +(pass) structured goldens (test-plan section 1) > combining-mark-fences: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.68ms] +(pass) structured goldens (test-plan section 1) > combining-mark-scalars: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.99ms] +(pass) structured goldens (test-plan section 1) > composition-empty-root: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [3.66ms] +(pass) structured goldens (test-plan section 1) > composition-shared-dag-unused: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [8.15ms] +(pass) structured goldens (test-plan section 1) > empty-document: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.46ms] +(pass) structured goldens (test-plan section 1) > empty-planes: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.92ms] +(pass) structured goldens (test-plan section 1) > extension-composition-instances: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [4.61ms] +(pass) structured goldens (test-plan section 1) > extension-document-unicode: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.85ms] +(pass) structured goldens (test-plan section 1) > extension-unicode-key-order: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [1.12ms] +(pass) structured goldens (test-plan section 1) > extension-unicode-source-collision: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.35ms] +(pass) structured goldens (test-plan section 1) > fences-and-directives: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.38ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-attribute-numeric-stays-string: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.20ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-axis-default: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.46ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-axis-lowercased: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.33ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-bom: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.22ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-code-block-directive-safe: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.15ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-coordinates-attributes: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.24ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-crlf: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.17ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-decimal-negative-z: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.17ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-empty-body: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.11ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-empty-plane-body: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.13ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-escaped-quote-label: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.16ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-frontmatter-comments: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.26ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-indented-directive-is-body: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.26ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-leading-blank-lines: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.23ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-metadata-key-case-preserved: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.33ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-multi-plane: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.34ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-plane-prefix-not-directive: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.15ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-preamble-with-planes: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.25ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-repeated-directive-key-last-wins: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.15ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-single-plane-shorthand: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.29ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-version-1-0: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.31ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-z-scientific-notation: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.40ms] +(pass) structured goldens (test-plan section 1) > mixed-coordinates: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.39ms] +(pass) structured goldens (test-plan section 1) > nfc-source-keys: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.26ms] +(pass) structured goldens (test-plan section 1) > scalar-quoting: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.44ms] +(pass) structured goldens (test-plan section 1) > unicode-exact-values: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.47ms] +(pass) structured goldens (test-plan section 1) > whitespace-crlf-bom: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.47ms] +(pass) structured goldens (test-plan section 1) > canopy: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.42ms] +(pass) structured goldens (test-plan section 1) > shared-grove: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [4.02ms] +(pass) structured goldens (test-plan section 1) > worked-document: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.35ms] +(pass) structured goldens (test-plan section 1) > worked-numbers: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.18ms] +(pass) structured goldens (test-plan section 1) > worked-keys: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.27ms] +(pass) structured goldens (test-plan section 1) > the worked document has the metrics of SPEC.md 11.3.17 and the annotated bytes [1.25ms] +(pass) structured vectors (test-plan section 2) > the manifest holds 156 vectors: 30 with limits, 25 ok, 131 typed errors [0.15ms] +(pass) structured vectors (test-plan section 2) > container-truncated-header (D4) gives invalidContainer [0.45ms] +(pass) structured vectors (test-plan section 2) > container-version-2 (D5) gives unsupportedVersion [0.20ms] +(pass) structured vectors (test-plan section 2) > container-kind-0 (D6) gives unsupportedPayloadKind [0.22ms] +(pass) structured vectors (test-plan section 2) > container-kind-3 (D6) gives unsupportedPayloadKind [0.08ms] +(pass) structured vectors (test-plan section 2) > container-kind-4 (D6) gives unsupportedPayloadKind [0.16ms] +(pass) structured vectors (test-plan section 2) > container-kind-255 (D6) gives unsupportedPayloadKind [0.09ms] +(pass) structured vectors (test-plan section 2) > container-kind-3-bad-crc (D6) gives unsupportedPayloadKind [0.07ms] +(pass) structured vectors (test-plan section 2) > container-compression-2 (D7) gives unsupportedCompression [0.10ms] +(pass) structured vectors (test-plan section 2) > container-flags (D8) gives unsupportedFlags [0.08ms] +(pass) structured vectors (test-plan section 2) > container-reserved (D9) gives nonzeroReserved [0.06ms] +(pass) structured vectors (test-plan section 2) > container-decoded-over-emax (D10) gives oversizedOutput [0.10ms] +(pass) structured vectors (test-plan section 2) > container-decoded-over-2dmax-bad-crc (D10) gives oversizedOutput [0.09ms] +(pass) structured vectors (test-plan section 2) > container-encoded-zero (D11) gives lengthMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > container-decoded-zero (D11) gives lengthMismatch [0.10ms] +(pass) structured vectors (test-plan section 2) > container-encoded-mismatch (D11) gives lengthMismatch [0.06ms] +(pass) structured vectors (test-plan section 2) > container-uncompressed-lengths-differ (D11) gives lengthMismatch [0.10ms] +(pass) structured vectors (test-plan section 2) > container-trailing-byte (D11) gives lengthMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > container-crc-field (D12) gives checksumMismatch [0.12ms] +(pass) structured vectors (test-plan section 2) > container-crc-payload (D12) gives checksumMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > container-lzfse-portable (D13) gives compressionUnavailable [0.10ms] +(pass) structured vectors (test-plan section 2) > var-non-minimal (V3) gives invalidContainer [0.19ms] +(pass) structured vectors (test-plan section 2) > var-non-minimal-zero (V3) gives invalidContainer [0.12ms] +(pass) structured vectors (test-plan section 2) > var-five-bytes (Str1) gives lengthMismatch [0.20ms] +(pass) structured vectors (test-plan section 2) > var-four-continuation-truncated (V1) gives lengthMismatch [0.18ms] +(pass) structured vectors (test-plan section 2) > var-truncated (V1) gives lengthMismatch [0.11ms] +(pass) structured vectors (test-plan section 2) > var-max-length (Str1) gives lengthMismatch [0.07ms] +(pass) structured vectors (test-plan section 2) > count-metadata (C) gives lengthMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > count-planes (C) gives lengthMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > count-attributes (C) gives lengthMismatch [0.19ms] +(pass) structured vectors (test-plan section 2) > count-planes-edge-ok (C) gives ok [0.13ms] +(pass) structured vectors (test-plan section 2) > count-planes-over-pmax-and-remaining (C) gives lengthMismatch [0.10ms] +(pass) structured vectors (test-plan section 2) > str-remaining-plus-one (Str1) gives lengthMismatch [0.12ms] +(pass) structured vectors (test-plan section 2) > str-remaining-before-limit (Str1) gives lengthMismatch [0.27ms] +(pass) structured vectors (test-plan section 2) > str-two-byte-var-exact-ok (Str1) gives ok [0.33ms] +(pass) structured vectors (test-plan section 2) > str-two-byte-var-plus-one (Str1) gives lengthMismatch [0.11ms] +(pass) structured vectors (test-plan section 2) > str-over-record (Str2) gives oversizedRecord [0.15ms] +(pass) structured vectors (test-plan section 2) > str-preamble-over-r-minus-1 (S7) gives oversizedRecord [0.11ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-overlong (Str3) gives invalidUTF8 [0.36ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-surrogate (Str3) gives invalidUTF8 [0.09ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-above-max (Str3) gives invalidUTF8 [0.08ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-truncated (Str3) gives invalidUTF8 [0.09ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-lone-continuation (Str3) gives invalidUTF8 [0.10ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-ff (Str3) gives invalidUTF8 [0.11ms] +(pass) structured vectors (test-plan section 2) > utf8-body-split (Str3) gives invalidUTF8 [0.07ms] +(pass) structured vectors (test-plan section 2) > utf8-before-line-break (Str3) gives invalidUTF8 [0.06ms] +(pass) structured vectors (test-plan section 2) > scalar-lf (Str4) gives invalidDocument [0.15ms] +(pass) structured vectors (test-plan section 2) > scalar-cr (Str4) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > flags-document-bit2 (S1) gives invalidContainer [0.07ms] +(pass) structured vectors (test-plan section 2) > flags-document-bit7 (S1) gives invalidContainer [0.06ms] +(pass) structured vectors (test-plan section 2) > flags-plane-bit7 (P1) gives invalidContainer [0.06ms] +(pass) structured vectors (test-plan section 2) > flags-plane-z-form-0 (P1) gives invalidContainer [0.08ms] +(pass) structured vectors (test-plan section 2) > number-f32-integer (N) gives invalidContainer [0.07ms] +(pass) structured vectors (test-plan section 2) > number-f32-negative-zero (N) gives invalidContainer [0.07ms] +(pass) structured vectors (test-plan section 2) > number-f32-nan (N) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > number-f32-infinity (N) gives invalidDocument [0.08ms] +(pass) structured vectors (test-plan section 2) > number-f32-truncated (N) gives lengthMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > number-f64-truncated (N) gives lengthMismatch [0.13ms] +(pass) structured vectors (test-plan section 2) > number-f64-integer (N) gives invalidContainer [0.09ms] +(pass) structured vectors (test-plan section 2) > number-f64-binary32 (N) gives invalidContainer [0.10ms] +(pass) structured vectors (test-plan section 2) > number-f64-negative-zero (N) gives invalidContainer [0.07ms] +(pass) structured vectors (test-plan section 2) > number-f64-nan (N) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > number-f64-negative-infinity (N) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > number-f64-int-boundary (N) gives invalidContainer [0.06ms] +(pass) structured vectors (test-plan section 2) > number-f32-two-pow-27-ok (N) gives ok [0.13ms] +(pass) structured vectors (test-plan section 2) > number-f64-two-pow-53-plus-2-ok (N) gives ok [0.17ms] +(pass) structured vectors (test-plan section 2) > number-f32-for-f64-value (N) gives ok [0.13ms] +(pass) structured vectors (test-plan section 2) > order-metadata-decreasing (S6) gives invalidContainer [0.10ms] +(pass) structured vectors (test-plan section 2) > order-metadata-identical (S6) gives invalidContainer [0.13ms] +(pass) structured vectors (test-plan section 2) > order-nfc-instead-of-bytes (S6) gives invalidContainer [0.11ms] +(pass) structured vectors (test-plan section 2) > order-utf16-instead-of-bytes (S6) gives invalidContainer [0.12ms] +(pass) structured vectors (test-plan section 2) > order-equivalent-keys (S6b) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > order-equivalent-kelvin (S6b) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > order-attributes-decreasing (P7) gives invalidContainer [0.11ms] +(pass) structured vectors (test-plan section 2) > order-attributes-equivalent (P7a) gives invalidDocument [0.08ms] +(pass) structured vectors (test-plan section 2) > order-keys-ok (S6) gives ok [0.20ms] +(pass) structured vectors (test-plan section 2) > field-empty-version (S2) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > axis-uppercase (R2) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > axis-leading-space (R2) gives invalidDocument [0.08ms] +(pass) structured vectors (test-plan section 2) > axis-trailing-tab (R2) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > axis-trailing-nbsp (R2) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > axis-non-ascii-uppercase (R2) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > axis-unicode-ok (R2) gives ok [0.11ms] +(pass) structured vectors (test-plan section 2) > metadata-key-colon (R3) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > metadata-key-hash (R3) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > metadata-key-leading-space (R3) gives invalidDocument [0.08ms] +(pass) structured vectors (test-plan section 2) > metadata-key-trailing-ideographic-space (R3) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > metadata-key-axis (R3) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > metadata-key-title (R3) gives invalidDocument [0.08ms] +(pass) structured vectors (test-plan section 2) > metadata-key-version (R3) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > metadata-key-empty-ok (R3) gives ok [0.16ms] +(pass) structured vectors (test-plan section 2) > attribute-key-empty (R9) gives invalidDocument [0.25ms] +(pass) structured vectors (test-plan section 2) > attribute-key-uppercase (R9) gives invalidDocument [0.24ms] +(pass) structured vectors (test-plan section 2) > attribute-key-label (R9) gives invalidDocument [0.21ms] +(pass) structured vectors (test-plan section 2) > attribute-key-z (R9) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > attribute-key-equals (R9) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > attribute-key-space (R9) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > attribute-key-tab (R9) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > attribute-key-leading-nbsp (R9) gives invalidDocument [0.08ms] +(pass) structured vectors (test-plan section 2) > attribute-key-sigma (R9) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > duplicate-z (L0) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > preamble-without-planes (S8) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > too-many-planes (S8) gives tooManyPlanes [0.09ms] +(pass) structured vectors (test-plan section 2) > segment-empty-preamble (G1) gives invalidDocument [0.16ms] +(pass) structured vectors (test-plan section 2) > segment-trailing-cr (G2) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > segment-inner-cr-ok (G2) gives ok [0.14ms] +(pass) structured vectors (test-plan section 2) > segment-crlf (G3) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > segment-leading-blank (G4) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > segment-trailing-blank (G4) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > segment-leading-nbsp-line (G4) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > segment-trailing-ideographic-line (G4) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > segment-plane-line (G5) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > segment-plane-directive (G5) gives invalidDocument [0.12ms] +(pass) structured vectors (test-plan section 2) > segment-plane-tab (G5) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > segment-indented-plane-ok (G5) gives ok [0.15ms] +(pass) structured vectors (test-plan section 2) > segment-planet-ok (G5) gives ok [0.14ms] +(pass) structured vectors (test-plan section 2) > segment-fence-backtick-tilde-ok (G5) gives ok [0.15ms] +(pass) structured vectors (test-plan section 2) > segment-fence-tilde-closed (G5) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > segment-fence-nbsp-indented-ok (G5) gives ok [0.20ms] +(pass) structured vectors (test-plan section 2) > segment-fence-open-not-final (G6) gives invalidDocument [0.13ms] +(pass) structured vectors (test-plan section 2) > segment-fence-open-final-ok (G6) gives ok [0.12ms] +(pass) structured vectors (test-plan section 2) > segment-fence-open-preamble (G6) gives invalidDocument [0.17ms] +(pass) structured vectors (test-plan section 2) > segment-bom-nul-ok (Str3) gives ok [0.14ms] +(pass) structured vectors (test-plan section 2) > phase-q-apostrophe (Q) gives invalidDocument [0.26ms] +(pass) structured vectors (test-plan section 2) > phase-q-double-quote (Q) gives invalidDocument [0.19ms] +(pass) structured vectors (test-plan section 2) > phase-q-paired-ok (Q) gives ok [0.31ms] +(pass) structured vectors (test-plan section 2) > phase-q-spaced-pair-ok (Q) gives ok [0.32ms] +(pass) structured vectors (test-plan section 2) > phase-q-quoted-space-ok (Q) gives ok [0.19ms] +(pass) structured vectors (test-plan section 2) > phase-q-swallow-next (Q) gives invalidDocument [0.18ms] +(pass) structured vectors (test-plan section 2) > phase-q-inject-z (Q) gives invalidDocument [0.18ms] +(pass) structured vectors (test-plan section 2) > phase-q-inject-label (Q) gives invalidDocument [0.21ms] +(pass) structured vectors (test-plan section 2) > phase-q-uppercase-quoted (Q) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > limit-record-below-3 (L1) gives oversizedRecord [0.23ms] +(pass) structured vectors (test-plan section 2) > limit-frontmatter-line (L2) gives oversizedRecord [0.22ms] +(pass) structured vectors (test-plan section 2) > limit-directive-line (L3) gives oversizedRecord [0.22ms] +(pass) structured vectors (test-plan section 2) > limit-text-length (L4) gives oversizedOutput [0.12ms] +(pass) structured vectors (test-plan section 2) > limit-lines (L5) gives tooManyLines [0.12ms] +(pass) structured vectors (test-plan section 2) > precedence-l0-over-l3 (L0) gives invalidDocument [0.20ms] +(pass) structured vectors (test-plan section 2) > precedence-l3-over-l4 (L3) gives oversizedRecord [0.17ms] +(pass) structured vectors (test-plan section 2) > precedence-l4-over-l5 (L4) gives oversizedOutput [0.19ms] +(pass) structured vectors (test-plan section 2) > precedence-s-order (S9) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > precedence-utf8-before-limits (S4) gives invalidUTF8 [0.08ms] +(pass) structured vectors (test-plan section 2) > end-trailing-byte (S10) gives lengthMismatch [0.10ms] +(pass) structured vectors (test-plan section 2) > bound-2dmax-exact (L4) gives oversizedOutput [0.07ms] +(pass) structured vectors (test-plan section 2) > eighty-planes-emax-1000 (L4) gives ok [0.24ms] +(pass) structured vectors (test-plan section 2) > edges-maximumDecodedBytes-at (L4) gives ok [0.37ms] +(pass) structured vectors (test-plan section 2) > edges-maximumDecodedBytes-below (L4) gives oversizedOutput [0.05ms] +(pass) structured vectors (test-plan section 2) > edges-maximumLines-at (L5) gives ok [0.10ms] +(pass) structured vectors (test-plan section 2) > edges-maximumLines-below (L5) gives tooManyLines [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumPlanes-at (S8) gives ok [0.07ms] +(pass) structured vectors (test-plan section 2) > edges-maximumPlanes-below (S8) gives tooManyPlanes [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumRecordBytes-at (L3) gives ok [0.09ms] +(pass) structured vectors (test-plan section 2) > edges-maximumRecordBytes-below (L3) gives oversizedRecord [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumEncodedBytes-at (D2) gives ok [0.08ms] +(pass) structured vectors (test-plan section 2) > edges-maximumEncodedBytes-below (D2) gives oversizedInput [0.08ms] +(pass) structured vectors (test-plan section 2) > preamble-record-31 (Str2) gives ok [0.08ms] +(pass) structured vectors (test-plan section 2) > preamble-record-30 (Str2) gives oversizedRecord [0.03ms] +(pass) structured unit checklist (test-plan section 3) > Var encodes and decodes minimally at every byte-count boundary [17.17ms] +(pass) structured unit checklist (test-plan section 3) > Var rejections V1 to V3 [0.55ms] +(pass) structured unit checklist (test-plan section 3) > number forms follow SPEC.md 11.3.3 and every encoding decodes bit for bit [0.52ms] +(pass) structured unit checklist (test-plan section 3) > CRC check value, slicing against a bytewise reference, and container checksums [78.91ms] +(pass) structured unit checklist (test-plan section 3) > chunked UTF-8 validation agrees with whole-string validation at every chunk boundary [12.55ms] +(pass) structured unit checklist (test-plan section 3) > segment rules G1 to G6 on hand cases [0.48ms] +(pass) structured unit checklist (test-plan section 3) > segment scanner agrees with the 2.0 parser round trip on 100,000 random bodies [1564.91ms] +(pass) structured unit checklist (test-plan section 3) > canonical text metrics equal the 2.0 writer on every Example and 100,000 generated documents [9950.91ms] +(pass) structured unit checklist (test-plan section 3) > byte-order keys: code point order equals UTF-8 byte order, never UTF-16 order [83.07ms] +(pass) structured unit checklist (test-plan section 3) > key equivalence matches normalize("NFC") on decode [0.74ms] +(pass) structured unit checklist (test-plan section 3) > numeric-powers.json: 4,318 canonical spellings [15.46ms] +(pass) structured unit checklist (test-plan section 3) > containerInfo reports raw header fields without validating them [0.75ms] +(pass) structured unit checklist (test-plan section 3) > encodeTextContainer keeps the 2.0 binary writer's bytes and error order [12.19ms] +(pass) structured unit checklist (test-plan section 3) > writer edges: W1b, the exact Emax cap, compression after the self-check [0.90ms] +(pass) structured unit checklist (test-plan section 3) > TypeScript writer: lone surrogates, equivalent-key merge, dropped values and __proto__ [0.86ms] +(pass) structured unit checklist (test-plan section 3) > the portable utf8Length path, where String.prototype.isWellFormed is missing, writes the same bytes [6.47ms] +(pass) structured unit checklist (test-plan section 3) > decoded values have the 2.0 bounded decoder's shape [0.26ms] +(pass) structured unit checklist (test-plan section 3) > Unicode skew vectors outside Unicode 13.0 (recorded for the runtime's Unicode data) [1.25ms] +(pass) structured unit checklist (test-plan section 3) > size gate G6 (perf-gate section 4) holds for the Examples and the committed large-input sizes [93.46ms] +(pass) structured unit checklist (test-plan section 3) > the package index exports exactly the two new storage names [0.46ms] +(pass) TypeScript chunked decoding never carries bytes into the next string > Bun: a truncated last chunk and the following string both report invalidUTF8 [27.83ms] +(pass) TypeScript chunked decoding never carries bytes into the next string > Node: the same two-call sequences on the current sources [131.85ms] +(pass) differential properties at CI volume (test-plan section 4) > P1, P2 and P3 over 10,410 mutants of every anchor and the kind-2 Examples (seed 0x51a7) [2363.24ms] +(pass) differential properties at CI volume (test-plan section 4) > P5: encode(D, L) succeeds exactly when decode(encode(D, L), L) does, and returns the normalized D [100.55ms] +(pass) differential properties at CI volume (test-plan section 4) > P6: binary acceptance equals validate under standard and lowered limits, and decode equals the text decode [804.06ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > before entry: a pre-aborted signal fails every storage entry point with its reason [0.20ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > every decode and encode check point aborts with the reason and leaves no partial result [33.11ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > mid-CRC on a 64 MiB input [301.50ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > inside a 1 MiB scalar scan and between the UTF-8 chunks of an 8 MiB body [190.80ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > before plane k of 65,536 and in Phase L [830.25ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > before and after a Phase Q parse [0.42ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > mid-emission and mid-self-check on encode [0.91ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > the result walk checks by bytes inside one plane of 700,000 attributes (standard limits) [1382.23ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > the equivalence checks of long decomposed keys check by bytes, metadata and attributes (standard limits) [557.26ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > the writer checks by work inside large maps: merge tests, sorts, the plan and the emission [1782.68ms] +Bun memory growth / input: body a: 2.61, body é: 2.60, body €: 2.34, body 😀: 2.61, planes: 2.13, attributes: 1.25 +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > memory on Bun: resident growth under 4 times the input for the 64 MiB worst cases and an 8 MiB body [1932.37ms] +Node memory growth / input: body a: 2.10, body é: 2.12, body €: 1.78, body 😀: 2.14, planes: 2.85, attributes: 1.03 +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > memory on Node: the same cases on the current sources [2206.19ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > amplification: 65,536 quoted-key planes over R are rejected before any Phase Q parse, in under a second [265.77ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > Phase S allocates nothing per key: 2,000,000 minimal attributes stay far below 4 times the input [775.50ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > buffer ownership: overwriting or slicing the caller's buffer never changes a decoded value [2.01ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > a kind-2 file whose uncompressed container exceeds Emax or 2 Dmax stops at D10 before the CRC [0.14ms] + +test/composition.test.ts: +(pass) bounded self-contained composition > safe ID grammar, duplicates, absent roots and unreachable missing targets fail [1.94ms] +(pass) bounded self-contained composition > cycles, unused cycles, cached depth and repeated-traversal occurrence limits fail [0.92ms] +(pass) bounded self-contained composition > counts, unique source bytes and per-reference UTF-8 attributes are bounded [0.30ms] +(pass) bounded self-contained composition > constructors enforce absolute integer limits and legitimate zero reference limits [0.07ms] +(pass) bounded self-contained composition > public graph codecs validate plain-object composition policies before reading or writing [0.16ms] +(pass) bounded self-contained composition > strict envelopes, schemas, unknown fields and JSON types are rejected [0.91ms] +(pass) bounded self-contained composition > duplicate escaped keys, nested records, numeric fields and trailing JSON fail before object decoding [0.73ms] +(pass) bounded self-contained composition > embedded paths and malformed unused sources stay local parse errors [0.48ms] +(pass) bounded self-contained composition > profile and escaped JSON bounds count the complete envelope [0.55ms] +(pass) bounded self-contained composition > opaque attributes preserve controls, Unicode and prototype-looking keys [0.44ms] +(pass) bounded self-contained composition > pre-aborted graph construction and codecs propagate cancellation [0.14ms] +(pass) bounded self-contained composition > new reference writers sort Unicode scalar keys and strict JSON rejects equivalent duplicate keys [1.29ms] + +test/conformance.test.ts: +(pass) conformance vectors > at least one valid and one invalid vector exist [0.31ms] +(pass) conformance vectors > invalid-duplicate-plane.json: two planes sharing the same z value are rejected [0.17ms] +(pass) conformance vectors > invalid-duplicate-z-decimal-forms.json: z=0 and z=0.0 are the same position [0.04ms] +(pass) conformance vectors > invalid-frontmatter-no-colon.json: frontmatter line without a colon separator is rejected [0.03ms] +(pass) conformance vectors > invalid-frontmatter-unclosed.json: frontmatter block that is never closed is rejected [0.02ms] +(pass) conformance vectors > invalid-missing-frontmatter.json: document without a frontmatter fence is rejected +(pass) conformance vectors > invalid-missing-plane-position.json: a plane directive with no z attribute is rejected [0.02ms] +(pass) conformance vectors > invalid-missing-version.json: frontmatter without the 3md version key is rejected [0.01ms] +(pass) conformance vectors > invalid-plane-token-no-equals.json: a plane attribute token with no equals sign is rejected (Swift throws; it is not skipped) [0.04ms] +(pass) conformance vectors > invalid-plane-x-not-number.json: a plane directive whose x is not a number is rejected [0.03ms] +(pass) conformance vectors > invalid-plane-z-not-number.json: a plane directive whose z is not a number is rejected [0.02ms] +(pass) conformance vectors > invalid-unterminated-quote.json: an unterminated quote in a directive is rejected [0.03ms] +(pass) conformance vectors > invalid-z-hex.json: hex z is rejected so Swift and TS agree [0.02ms] +(pass) conformance vectors > invalid-z-infinity.json: z=inf is rejected (non-finite) [0.01ms] +(pass) conformance vectors > invalid-z-nan.json: z=nan is rejected (non-finite, also closes the NaN dedup bypass) +(pass) conformance vectors > invalid-z-thousands-separator.json: thousands separators are rejected +(pass) conformance vectors > links-basic.json: a [[z=N]] reference resolves to the source z, target z, and existence [0.14ms] +(pass) conformance vectors > links-dangling.json: a reference to a missing plane is reported with targetExists false [0.01ms] +(pass) conformance vectors > links-decimal-target.json: a decimal target z is matched against a decimal plane z [0.01ms] +(pass) conformance vectors > links-invalid-ignored.json: non-finite targets and ordinary Markdown links are not cross-plane links +(pass) conformance vectors > links-multiple.json: multiple links in one body are returned left to right [0.01ms] +(pass) conformance vectors > links-with-text.json: a [[z=N|text]] reference captures the link text [0.01ms] +(pass) conformance vectors > valid-attribute-numeric-stays-string.json: non z/x/y attributes stay strings, not coerced [0.04ms] +(pass) conformance vectors > valid-axis-default.json: axis defaults to layer when omitted +(pass) conformance vectors > valid-axis-lowercased.json: axis value is trimmed and lowercased +(pass) conformance vectors > valid-bom.json: a leading UTF-8 BOM is stripped before parsing +(pass) conformance vectors > valid-code-block-directive-safe.json: a @plane line inside a fenced code block stays body text +(pass) conformance vectors > valid-coordinates-attributes.json: coordinates, label, and extra attributes are captured [0.02ms] +(pass) conformance vectors > valid-crlf.json: CRLF line endings are normalized to LF [0.01ms] +(pass) conformance vectors > valid-decimal-negative-z.json: z accepts negative and decimal values and keeps source order +(pass) conformance vectors > valid-empty-body.json: frontmatter only with no body yields no planes +(pass) conformance vectors > valid-empty-plane-body.json: a plane directive with no following content has an empty body +(pass) conformance vectors > valid-escaped-quote-label.json: escaped quotes inside a quoted label round-trip +(pass) conformance vectors > valid-frontmatter-comments.json: frontmatter skips comment and blank lines and strips quotes [0.01ms] +(pass) conformance vectors > valid-indented-directive-is-body.json: an indented @plane is body, not a directive [0.01ms] +(pass) conformance vectors > valid-leading-blank-lines.json: leading blank lines before the frontmatter fence are allowed +(pass) conformance vectors > valid-metadata-key-case-preserved.json: non-reserved frontmatter keys keep their case +(pass) conformance vectors > valid-multi-plane.json: valid multi-plane document with title, metadata, and preamble [0.02ms] +(pass) conformance vectors > valid-plane-prefix-not-directive.json: @planex is not a directive; the doc is single-plane shorthand +(pass) conformance vectors > valid-preamble-with-planes.json: preamble is preserved when planes follow and quoted attribute keeps spaces [0.03ms] +(pass) conformance vectors > valid-repeated-directive-key-last-wins.json: a repeated directive key takes the last value [0.02ms] +(pass) conformance vectors > valid-single-plane-shorthand.json: single-plane shorthand wraps body at z=0 when no directives +(pass) conformance vectors > valid-version-1-0.json: the 1.0 format marker parses, with version reported as 1.0 +(pass) conformance vectors > valid-z-scientific-notation.json: scientific notation in z parses as a decimal [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-attribute-numeric-stays-string.json: non z/x/y attributes stay strings, not coerced [0.11ms] +(pass) round trip: parse -> serialize -> parse > valid-axis-default.json: axis defaults to layer when omitted [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-axis-lowercased.json: axis value is trimmed and lowercased [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-bom.json: a leading UTF-8 BOM is stripped before parsing [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-code-block-directive-safe.json: a @plane line inside a fenced code block stays body text [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-coordinates-attributes.json: coordinates, label, and extra attributes are captured [0.05ms] +(pass) round trip: parse -> serialize -> parse > valid-crlf.json: CRLF line endings are normalized to LF [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-decimal-negative-z.json: z accepts negative and decimal values and keeps source order [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-empty-body.json: frontmatter only with no body yields no planes +(pass) round trip: parse -> serialize -> parse > valid-empty-plane-body.json: a plane directive with no following content has an empty body [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-escaped-quote-label.json: escaped quotes inside a quoted label round-trip [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-frontmatter-comments.json: frontmatter skips comment and blank lines and strips quotes [0.03ms] +(pass) round trip: parse -> serialize -> parse > valid-indented-directive-is-body.json: an indented @plane is body, not a directive [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-leading-blank-lines.json: leading blank lines before the frontmatter fence are allowed [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-metadata-key-case-preserved.json: non-reserved frontmatter keys keep their case [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-multi-plane.json: valid multi-plane document with title, metadata, and preamble [0.05ms] +(pass) round trip: parse -> serialize -> parse > valid-plane-prefix-not-directive.json: @planex is not a directive; the doc is single-plane shorthand +(pass) round trip: parse -> serialize -> parse > valid-preamble-with-planes.json: preamble is preserved when planes follow and quoted attribute keeps spaces [0.03ms] +(pass) round trip: parse -> serialize -> parse > valid-repeated-directive-key-last-wins.json: a repeated directive key takes the last value [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-single-plane-shorthand.json: single-plane shorthand wraps body at z=0 when no directives +(pass) round trip: parse -> serialize -> parse > valid-version-1-0.json: the 1.0 format marker parses, with version reported as 1.0 +(pass) round trip: parse -> serialize -> parse > valid-z-scientific-notation.json: scientific notation in z parses as a decimal [0.02ms] + +test/editing.test.ts: +(pass) portable atomic editing and diagnostics > adoption skips existing IDs, preserves id metadata and rejects unsafe or duplicated identities [0.72ms] +(pass) portable atomic editing and diagnostics > snapshots deep-copy and freeze values; reconstruction rejects a forged revision [1.01ms] +(pass) portable atomic editing and diagnostics > insert, move, remove and header replacements are one pure transaction [0.52ms] +(pass) portable atomic editing and diagnostics > later invalid operation rolls back; replacement identities, indices and missing targets are precise [0.51ms] +(pass) portable atomic editing and diagnostics > exact revisions reject NFC-equivalent bytes and expected-content budgets [0.40ms] +(pass) portable atomic editing and diagnostics > structurally typed snapshot revisions cannot replace the exact-content comparison [0.94ms] +(pass) portable atomic editing and diagnostics > operation, payload and final invalid-document policies return no partial result [0.59ms] +(pass) portable atomic editing and diagnostics > two NaN coordinate replacements reach invalid-document validation without a false duplicate [0.23ms] +(pass) portable atomic editing and diagnostics > graph patches allow forward definitions and final root swaps without flattening [1.86ms] +(pass) portable atomic editing and diagnostics > graph final failures identify the missing target or root and enforce scoped IDs [1.97ms] +(pass) portable atomic editing and diagnostics > source diagnostics carry only actual parser lines; value paths and truncation stay precise [0.46ms] +(pass) portable atomic editing and diagnostics > diagnostic payload preflight precedes expensive graph validation and retains owner paths [4.30ms] +(pass) portable atomic editing and diagnostics > all identity, transaction and diagnostic entry points honor pre-aborted signals [0.50ms] +(pass) portable atomic editing and diagnostics > public editor and diagnostic boundaries reject forged plain-object policies [0.32ms] + +test/storage.test.ts: +(pass) bounded portable storage > fixed envelope vectors match Swift and sliced data retains its byte offset [0.20ms] +(pass) bounded portable storage > existing Swift canopy and grove envelopes remain readable and byte-identical [1.83ms] +(pass) bounded portable storage > LZFSE is explicitly unavailable while unknown compression remains a different error [0.19ms] +(pass) bounded portable storage > header fields, checksums, trailing bytes and unsafe 64-bit lengths are checked [0.27ms] +(pass) bounded portable storage > the same header, checksum and payload checks hold for payload kind 2 [0.18ms] +(pass) bounded portable storage > resource constructors reject noninteger and nonpositive limits and accept any safe size [0.15ms] +(pass) bounded portable storage > a document past the old 64 MiB ceiling round-trips as text and as kind 2 [2464.71ms] +(pass) bounded portable storage > public storage boundaries validate structurally typed plain-object policies [0.23ms] +(pass) bounded portable storage > exact byte boundaries succeed; physical lines, planes and entire records are bounded [0.32ms] +(pass) bounded portable storage > preflight respects code fences and preserves the existing parser/serializer behavior [0.11ms] +(pass) bounded portable storage > direct lossy values and malformed decimals fail without changing legacy text APIs [3.08ms] +(pass) bounded portable storage > hostile interior and trailing ASCII whitespace remains exact through text and portable storage [28.56ms] +(pass) bounded portable storage > pre-aborted operations propagate the abort reason [0.20ms] +(pass) bounded portable storage > new canonical maps use Swift Unicode key equality, scalar order and original spelling [0.58ms] + +test/interchange-adapter.test.ts: +(pass) development files adapter limits > limit literals are judged by their correctly rounded IEEE double, like Swift and Rust [111.22ms] + +test/extensions.test.ts: +(pass) Swift portable extension conformance > all IEEE754 number vectors match Swift canonical formatting [1.18ms] +(pass) Swift portable extension conformance > Swift scientific notation starts strictly above the exact 2^53 boundary [0.07ms] +(pass) Swift portable extension conformance > canonical Unicode document text, envelope and revision are byte-identical to Swift [0.98ms] +(pass) Swift portable extension conformance > canonical composition preserves shared definitions, instance IDs and exact profile bytes [2.72ms] +(pass) Swift portable extension conformance > additive Swift Unicode key ordering and source-collision goldens match the portable codecs [1.65ms] +(pass) Swift portable extension conformance > identity adoption follows the Swift fixture and preserves ordinary id metadata [0.89ms] +(pass) Swift portable extension conformance > document transaction: atomic-coordinate-swap [0.42ms] +(pass) Swift portable extension conformance > document transaction: source-order-change [0.23ms] +(pass) Swift portable extension conformance > composition transaction: retarget-and-reorder-owner-instance [1.56ms] +(pass) Swift portable extension conformance > composition transaction: remove-one-repeated-target-instance [1.39ms] +(pass) Swift portable extension conformance > atomic failure: stale-document-revision [0.26ms] +(pass) Swift portable extension conformance > atomic failure: final-coordinate-conflict [0.14ms] +(pass) Swift portable extension conformance > atomic failure: changed-plane-identity [0.13ms] +(pass) Swift portable extension conformance > atomic failure: stale-composition-revision [0.05ms] +(pass) Swift portable extension conformance > atomic failure: final-reference-cycle [0.66ms] +(pass) Swift portable extension conformance > atomic failure: wrong-owner-reference-target [0.42ms] + +test/file-composition.test.ts: +(pass) explicit supplied-file composition > simple and repeated glyph links deduplicate files and refresh changed child bytes [1.75ms] +(pass) explicit supplied-file composition > nested parent paths and duplicate basenames resolve relative to each containing file [1.34ms] +(pass) explicit supplied-file composition > payload kind 1 children and bundles (the 2.0 binary bytes) still resolve [1.30ms] +(pass) explicit supplied-file composition > binary nested bundles retain unused entries, stable identities and opaque edges before new ledger edges [1.84ms] +(pass) explicit supplied-file composition > nested profile records use the outer composition policy while embedded ordinary records retain child bounds [2596.10ms] +(pass) explicit supplied-file composition > paths use NFC and Unicode scalar ordering rather than UTF16 or locale sorting [1.41ms] +(pass) explicit supplied-file composition > path grammar rejects escape, absolute paths, empty segments, controls and normalized aliases [0.63ms] +(pass) explicit supplied-file composition > strict ledger scanner rejects duplicate escaped keys, malformed JSON and invalid glyphs before values [0.48ms] +(pass) explicit supplied-file composition > missing files and malformed reachable storage retain distinct errors, unreachable storage is ignored [0.38ms] +(pass) explicit supplied-file composition > file cycles also fail when unused bundle entries form a cycle across files [1.35ms] +(pass) explicit supplied-file composition > supplied counts, original path bytes and reachable bytes use input limits before decoding [154.17ms] +(pass) explicit supplied-file composition > outer recognition applies child byte and line policies before its lowered plane ceiling [0.62ms] +(pass) explicit supplied-file composition > disconnected embedded ledgers use final entry depth rather than incoming file depth [0.91ms] +(pass) explicit supplied-file composition > repeated cached dependencies validate final depth after complete discovery [0.86ms] +(pass) explicit supplied-file composition > independent fixed64 discovery safety bounds disconnected file chains [59.10ms] +(pass) explicit supplied-file composition > lowered policies enforce final graph depth, imported entries, edges, conceptual traversal and final profile size [1.28ms] +(pass) explicit supplied-file composition > pre-aborted and cooperatively aborted operations propagate the caller's cancellation reason [1.02ms] +(pass) linked composition parity hardening > static resolve, ledger and resolvePath do not depend on their class binding [1.00ms] +(pass) linked composition parity hardening > owner directories keep parent, dot and grammar semantics [0.15ms] +(pass) linked composition parity hardening > a long owner path with many references resolves every reference in its directory [9.66ms] +(pass) linked composition parity hardening > refusals follow entry ID, then glyph, discovery order [1.20ms] +(pass) linked composition parity hardening > root and unreachable supplied paths use the ledger path grammar [0.82ms] +(pass) linked composition parity hardening > ledger escapes decode before path grammar [0.82ms] +(pass) linked composition parity hardening > self and alias cycles compare normalized paths [0.38ms] +(pass) linked composition parity hardening > a cached subtree is charged at its deeper occurrence against the discovery ceiling [50.83ms] +(pass) linked composition parity hardening > existing edges precede ledger edges; embedded ledgers resolve from their bundle folder; output rebundles [1.74ms] +(pass) linked composition parity hardening > the source-file attribute bound counts normalized UTF-8 bytes [12.81ms] +(pass) linked composition parity hardening > lowered policies charge original path bytes before path grammar; invalid limits are refused first [0.34ms] +(pass) linked composition parity hardening > an abort inside the ledger scanner propagates the caller's reason [2.48ms] +(pass) linked composition parity hardening > an abort inside the scalar path sort propagates the caller's reason [2.36ms] +(pass) early source-file attribute bound and long-directory owners > an over-bound ledger edge is refused while resolving, before later refusals [0.59ms] +(pass) early source-file attribute bound and long-directory owners > the attribute bound counts normalized directory prefix bytes [0.56ms] +(pass) early source-file attribute bound and long-directory owners > long-directory owners resolve repeated sources once and refuse over-bound targets at the first edge [261.65ms] + +test/links.test.ts: +(pass) links() > basic reference resolves source, target, and existence [0.80ms] +(pass) links() > captures optional link text [0.04ms] +(pass) links() > present-but-empty link text is the empty string [0.02ms] +(pass) links() > multiple links in one body are returned left to right [0.02ms] +(pass) links() > links across planes follow source order [0.02ms] +(pass) links() > dangling reference reports targetExists false [0.02ms] +(pass) links() > decimal target matches a decimal plane z [0.02ms] +(pass) links() > non-finite and non-link sequences are ignored [0.01ms] +(pass) links() > signed and exponent targets parse as finite decimals [0.02ms] +(pass) links() > a document with no links returns an empty array [0.01ms] +(pass) links() > danglingLinks filters only missing targets [0.04ms] +(pass) links() > linkGraph collapses repeated source-target pairs [0.09ms] +(pass) links() > linkGraph keeps dangling edge status [0.04ms] + + 431 pass + 0 fail + 764396 expect() calls +Ran 431 tests across 10 files. [31.55s] + ✔ Step 4 done (33.639s) + ▶️ Running task: rust + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s + Finished `test` profile [unoptimized + debuginfo] target(s) in 0.10s + Running unittests src/lib.rs (target/debug/deps/threemd-3e8d3a72ef8b0b84) + +running 18 tests +test checksum::tests::check_value_matches_the_specification ... ok +test structured::tests::var_round_trips_at_every_size_boundary_and_rejects_v1_to_v3 ... ok +test structured::tests::number_forms_follow_the_table_and_decode_bit_exactly ... ok +test structured::tests::equivalence_is_rejected_only_for_canonically_equal_distinct_keys ... ok +test structured::tests::line_feed_bits_mark_exactly_the_line_feeds ... ok +test structured::tests::checked_chars_stop_at_a_failed_check_and_keep_the_error ... ok +test structured::tests::long_key_hashes_and_nfc_forms_check_cancellation_on_their_input ... ok +test structured::tests::every_cancellation_check_cancels_decode_and_encode_without_a_result ... ok +test structured::tests::phase_s_checks_cancellation_within_long_keys_and_axes ... ok +test checksum::tests::slicing_matches_the_bytewise_reference_at_every_alignment ... ok +test structured::tests::cancellation_reaches_long_scans_and_every_plane ... ok +test structured::tests::lowercase_test_agrees_with_to_lowercase ... ok +test structured::tests::w2_checks_cancellation_between_short_keys_and_within_long_keys ... ok +test structured::tests::phase_q_normalizes_each_key_once_in_the_2_0_writer_order ... ok +test structured::tests::equivalence_matches_brute_force_and_compares_forms_only_when_hashes_meet ... ok +test structured::tests::cancellation_reaches_the_crc_of_a_64_mib_input ... ok +test structured::tests::phase_q_runs_only_after_phase_l_bounds_every_directive ... ok +test structured::tests::long_key_nfc_test_agrees_with_is_nfc_and_checks_every_chunk ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.66s + + Running tests/conformance.rs (target/debug/deps/conformance-283cd1b2cb105be9) + +running 1 test +test conformance_vectors_pass ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/editing.rs (target/debug/deps/editing-997e6fa6b85c2c5a) + +running 9 tests +test direct_btree_maps_reject_ambiguous_canonically_equivalent_keys ... ok +test operation_payload_and_final_document_policies_are_enforced ... ok +test adopted_entries_report_the_specific_graph_error_that_adoption_wraps ... ok +test all_document_operations_preserve_source_order_and_header_fields ... ok +test identity_adoption_is_explicit_and_scoped ... ok +test graph_revision_roundtrip_diagnostics_and_cancellation ... ok +test document_operation_failures_are_structured_and_do_not_mutate_input ... ok +test all_composition_operations_validate_the_final_graph_atomically ... ok +test graph_failures_validate_counts_identity_and_reference_existence ... ok + +test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/extensions.rs (target/debug/deps/extensions-4eb0504670bb68cf) + +running 15 tests +test binary_header_fields_and_corruption_are_rejected ... ok +test bounded_diagnostics_preserve_real_parser_lines_and_legacy_ids ... ok +test graph_validates_unused_entries_cycles_and_resource_limits ... ok +test canonical_decimal_ties_use_nearest_even_shortest_spelling ... ok +test storage_resource_policies_and_faithful_value_validation ... ok +test exact_utf8_revision_reopen_and_forged_snapshot_validation ... ok +test original_extension_artifacts_and_lzfse_unavailability ... ok +test swift_unicode_key_order_and_source_collision_semantics_match ... ok +test composition_json_is_strict_and_rejects_decoded_duplicate_keys ... ok +test cancellation_propagates_without_publishing_values ... ok +test swift_numeric_vectors_match_exact_storage_spelling ... ok +test swift_document_and_composition_goldens_are_byte_identical ... ok +test swift_adoption_transactions_and_failures_match_semantics ... ok +test every_signed_power_of_two_and_ten_matches_the_shared_canonical_spelling ... ok +test a_document_past_the_old_ceiling_round_trips ... ok + +test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.43s + + Running tests/file_composition.rs (target/debug/deps/file_composition-82fdc3545091eafc) + +running 30 tests +test owner_directory_resolution_keeps_parent_dot_and_grammar_semantics ... ok +test outer_recognition_preserves_child_byte_and_line_policy_precedence_over_planes ... ok +test lowered_policy_charges_original_path_bytes_before_grammar_and_rejects_invalid_limits_first ... ok +test outer_profile_records_are_independent_of_child_record_policy ... ok +test over_bound_ledger_edge_is_refused_while_resolving_before_later_refusals ... ok +test ledger_is_strict_json_with_ascii_glyph_validation_before_duplicate_checks ... ok +test missing_files_and_file_cycles_include_ledgers_in_unused_bundle_entries ... ok +test attribute_bound_counts_normalized_directory_prefix_bytes ... ok +test final_depth_checks_include_cached_dependencies_and_cancelled_operations_are_atomic ... ok +test existing_edges_precede_ledger_edges_and_embedded_ledgers_resolve_from_their_bundle_folder ... ok +test disconnected_embedded_ledgers_use_actual_entry_depth_and_repeated_cached_files ... ok +test ledger_escapes_decode_before_path_grammar ... ok +test nested_relative_paths_keep_duplicate_basenames_and_use_scalar_order ... ok +test resolver_output_rebundles_with_opaque_glyph_and_source_file_attributes ... ok +test repeated_cached_files_validate_final_depth_and_missing_discovery_precedence ... ok +test refusals_follow_entry_id_then_glyph_discovery_order ... ok +test repeated_links_are_deterministic_and_preserve_the_ordinary_document ... ok +test self_and_alias_cycles_compare_normalized_paths ... ok +test unreachable_content_is_ignored_but_every_supplied_path_is_validated ... ok +test root_and_unreachable_supplied_paths_use_the_ledger_path_grammar ... ok +test supplied_and_resolved_policies_are_checked_before_returning_a_bundle ... ok +test binary_children_and_nested_bundles_preserve_unused_entries_and_reference_ids ... ok +test source_file_attribute_bound_counts_normalized_utf8_bytes ... ok +test discovery_ceiling_is_the_standard_maximum_depth ... ok +test fixed_file_discovery_ceiling_bounds_disconnected_chains ... ok +test long_owner_path_with_many_references_resolves_every_reference_in_its_directory ... ok +test cached_subtree_is_charged_at_its_deeper_occurrence_against_the_discovery_ceiling ... ok +test long_directory_owners_resolve_repeated_sources_once_and_refuse_over_bound_targets_early ... ok +test project_paths_have_explicit_rules_and_bounded_standalone_work ... ok +test cancellation_from_another_thread_during_resolution_returns_no_result ... ok + +test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.69s + + Running tests/interchange.rs (target/debug/deps/interchange-1ce7f8e1fb0daa3c) + +running 5 tests +test bounded_parse_keeps_limits_and_explicit_cancellation ... ok +test source_unicode_aliases_keep_first_spelling_and_last_value_in_both_parsers ... ok +test legacy_serializer_preserves_quoted_apostrophes_and_boundary_whitespace ... ok +test raw_and_bounded_parsers_share_foundation_horizontal_whitespace ... ok +test large_unique_plane_sets_and_numeric_duplicate_equality_are_preserved ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.46s + + Running tests/structured.rs (target/debug/deps/structured-e12e8226d3e976db) + +running 24 tests +test p1_to_p4_every_mutant_reports_the_shared_outcome ... ignored, 102,600 decodes; run with --release -- --ignored +test container_info_reports_raw_fields_without_validation ... ok +test unicode_skew_vectors_follow_this_toolchains_data ... ok +test payload_kind_dispatch_and_the_decoded_length_bound ... ok +test worked_examples_have_the_specified_bytes ... ok +test writer_cap_negative_zero_and_compression_follow_w1_to_w6 ... ok +test a_truncated_tail_never_carries_into_the_next_string_or_call ... ok +test compositions_accept_kind_1_and_2_envelopes_and_refuse_kind_3 ... ok +test text_container_writer_keeps_the_2_0_bytes_and_error_order ... ok +test new_types_are_send_and_sync_and_codecs_run_from_32_threads ... ok +test every_golden_is_reproduced_byte_for_byte_and_decodes_to_the_text_decode ... ok +test var_prefixes_at_size_boundaries_round_trip_through_bodies ... ok +test every_vector_reports_its_code_under_its_limits ... ok +test number_forms_round_trip_bit_exactly_and_spell_canonically ... ok +test g6_kind_2_sizes_match_sizes_json ... ok +test keys_are_written_in_byte_order_and_equivalent_spellings_are_rejected ... ok +test chunked_utf8_validation_agrees_with_whole_string_validation ... ok +test cancellation_returns_no_value_and_leaves_inputs_reusable ... ok +test p5_p6_writer_acceptance_equals_validate_under_standard_limits ... ok +test p5_p6_writer_acceptance_equals_validate_under_lowered_limits ... ok +test metrics_equal_the_canonical_text_on_every_example ... ok +test p1_to_p4_mutants_report_the_shared_outcomes ... ok +test segment_rules_agree_with_the_text_round_trip_on_random_bodies ... ok +test metrics_equal_the_canonical_text_on_generated_documents ... ok + +test result: ok. 23 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 6.91s + + Running tests/structured_memory.rs (target/debug/deps/structured_memory-4f6ad24055334ee6) + +running 1 test +test kind_2_decoding_stays_under_four_times_the_input ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.58s + + Running unittests examples/interchange.rs (target/debug/examples/interchange-3e1831aec2fdc659) + +running 9 tests +test tests::hex_is_exact_and_rejects_uppercase_or_odd_input ... ok +test tests::document_adapter_edits_and_rejects_stale_patch_for_both_file_formats ... ok +test tests::malformed_protocol_keys_numbers_and_depth_precede_source_count ... ok +test tests::supplied_file_adapter_emits_reopenable_composition_outputs ... ok +test tests::supplied_file_adapter_rejects_malformed_protocol_and_maps_core_errors ... ok +test tests::composition_adapter_preserves_references_and_binary_parity ... ok +test tests::file_limits_are_strict_shapes_with_library_validated_values ... ok +test tests::oversized_requests_are_consumed_and_responses_are_atomic ... ok +test tests::supplied_file_count_precedes_source_shape_validation_but_not_top_level_validation ... ok + +test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Finished `test` profile [unoptimized + debuginfo] target(s) in 0.03s + Doc-tests threemd + +running 4 tests +test src/lib.rs - ParseError::code (line 178) ... ok +test src/lib.rs - axis (line 67) ... ok +test src/storage.rs - storage::DocumentContainerInfo (line 216) ... ok +test src/lib.rs - (line 12) ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.57s + + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s + ✔ Step 5 done (35.809s) + ▶️ Running task: interchange +[0/1] Planning build +Building for debugging... +[0/3] Write swift-version--58304C5D6DBC2206.txt +Build of product 'threemd-interchange' complete! (0.21s) +{"cases":569,"compression":"none; optional Apple LZFSE excluded","imports":17991,"pairCounts":{"Rust -> Rust":1999,"Rust -> Swift":1999,"Rust -> TypeScript-Node":1999,"Swift -> Rust":1999,"Swift -> Swift":1999,"Swift -> TypeScript-Node":1999,"TypeScript-Node -> Rust":1999,"TypeScript-Node -> Swift":1999,"TypeScript-Node -> TypeScript-Node":1999},"passed":true,"producerConsumerPairs":9,"schema":"3md-interchange-receipt-1"} +Interchange evidence: /var/folders/5k/616qy7sj28l0d53k4c6w_4x00000gn/T/3md-interchange-071A812B-699B-49C2-AE1B-52282BBC1E37 + ✔ Step 6 done (58.685s) + ▶️ Running task: element-bundle +Bundled 10 modules in 16ms + + three-md.js 48.84 KB (entry point) + +element bundle is current (48840 bytes, no storage code) + ✔ Step 7 done (96ms) + ▶️ Running task: editor +bun install v1.4.0 (34cbb9a40) + +Checked 183 installs across 192 packages (no changes) [87.00ms] +$ vscode-tmgrammar-test -g syntaxes/3md.tmLanguage.json -g syntaxes/3md-links.injection.json -g tests/grammars/markdown.tmLanguage.json "tests/*.3md" +grammar not found for "source.yaml" +grammar not found for "text.html.derivative" +grammar not found for "source.css" +grammar not found for "text.html.basic" +grammar not found for "source.ini" +grammar not found for "source.java" +grammar not found for "source.lua" +grammar not found for "source.makefile" +grammar not found for "source.perl" +grammar not found for "source.r" +grammar not found for "source.ruby" +grammar not found for "source.php" +grammar not found for "source.sql" +grammar not found for "source.asp.vb.net" +grammar not found for "text.xml" +grammar not found for "text.xml.xsl" +grammar not found for "source.batchfile" +grammar not found for "source.clojure" +grammar not found for "source.coffee" +grammar not found for "source.c" +grammar not found for "source.cpp" +grammar not found for "source.diff" +grammar not found for "source.dockerfile" +grammar not found for "text.git-commit" +grammar not found for "text.git-rebase" +grammar not found for "source.go" +grammar not found for "source.groovy" +grammar not found for "text.pug" +grammar not found for "source.ignore" +grammar not found for "source.js" +grammar not found for "source.js.regexp" +grammar not found for "source.json" +grammar not found for "source.json.comments" +grammar not found for "source.json.lines" +grammar not found for "source.css.less" +grammar not found for "source.objc" +grammar not found for "source.swift" +grammar not found for "source.css.scss" +grammar not found for "source.perl.6" +grammar not found for "source.powershell" +grammar not found for "source.python" +grammar not found for "source.julia" +grammar not found for "source.regexp.python" +grammar not found for "source.rust" +grammar not found for "source.scala" +grammar not found for "source.shell" +grammar not found for "source.ts" +grammar not found for "source.tsx" +grammar not found for "source.cs" +grammar not found for "source.fsharp" +grammar not found for "source.dart" +grammar not found for "text.html.handlebars" +grammar not found for "text.log" +grammar not found for "source.erlang" +grammar not found for "source.elixir" +grammar not found for "text.tex.latex" +grammar not found for "text.bibtex" +grammar not found for "source.twig" +grammar not found for "source.yang" +grammar not found for "source.abap" +grammar not found for "source.rst" +✓ tests/cross-plane-link.3md run successfuly. +✓ tests/frontmatter.3md run successfuly. +✓ tests/markdown-body.3md run successfuly. +✓ tests/plane-directive.3md run successfuly. + ✔ Step 8 done (500ms) +✅ Lane verify completed (8 steps in 3m 41.135s) +⊘ Skipped 3 unchanged spec(s) (use --force/--no-cache to re-validate all) + ℹ Cache: /Users/leif/Development/_CorvidLabs/3md-edit-preview/.specsync/hashes.json + + +specs/ThreeMDViewer/ThreeMDViewer.spec.md + ✓ Frontmatter valid + ✓ All source files exist + ✓ All required sections present + ✓ 20/20 exports documented + ✓ All dependency specs exist + +4 specs checked: 4 passed, 0 warning(s), 0 failed +File coverage: 55/55 (100%) +LOC coverage: 21185/21185 (100%) +augur: config: loaded ./.augur.toml +From https://github.com/CorvidLabs/3md + + 051c408...3340e6c refs/notes/attest -> refs/notes/attest (forced update) +trust range: origin/leif/viewer-draft-navigation..HEAD +== lifecycle == +== contract == +== risk == +== provenance == +== atlas: off (Atlas publication was not enabled during adoption) == +trust gate passed (progressive provenance) diff --git a/specs/ThreeMDViewer/ThreeMDViewer.spec.md b/specs/ThreeMDViewer/ThreeMDViewer.spec.md index fc965bb..ce21aeb 100644 --- a/specs/ThreeMDViewer/ThreeMDViewer.spec.md +++ b/specs/ThreeMDViewer/ThreeMDViewer.spec.md @@ -1,6 +1,6 @@ --- module: ThreeMDViewer -version: 13 +version: 15 status: active files: - web/viewer.html @@ -162,6 +162,8 @@ Acceptance Criteria: | 2026-10-10 | agent:codex | Preserve the slice across editor refresh, sort file paths for consistent keyboard navigation, and compact small-phone spacing. Leif approved the final scope; verification, acceptance, and archiving are pending. | | 2026-10-10 | SpecSync | put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below: Put Edit and Preview in the same viewer panel and toggle them like GitHub. Files stay on the left. Edit shows first. Below 900px, Files and the document take turns, and the document panel still switches Edit and Preview. | | 2026-10-10 | SpecSync | keep-sculpt-and-web-cube-cameras-in-parity-with-unrestricted-orbit-and-screen-space-pan: Keep Sculpt and web cube cameras in parity with unrestricted orbit and screen-space pan | +| 2026-10-10 | SpecSync | bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference: Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference | +| 2026-10-10 | SpecSync | add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer: Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer | ## Slice and precise camera parity diff --git a/specs/ThreeMDViewer/requirements.md b/specs/ThreeMDViewer/requirements.md index 59b8294..9119e98 100644 --- a/specs/ThreeMDViewer/requirements.md +++ b/specs/ThreeMDViewer/requirements.md @@ -48,13 +48,12 @@ Acceptance Criteria: ### REQ-ThreeMDViewer-003 -The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. +The viewer page SHALL show Edit, Preview, Cubes, and Slice in one panel. Exactly one main view SHALL be visible; Slice SHALL include a live 3D reference within its workspace. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, Cubes, and Slice. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. The Slice workspace SHALL preserve the current selected plane, camera and source when entering or leaving the view. Acceptance Criteria: -- At a desktop width, files stay visible. Cubes shows first, and the lit cubes are inside the window. Edit shows the editor and hides the cubes. Preview shows the live plane view and hides the editor. -- At 800px, Files and the document take turns. The document panel still switches Edit, Preview, and Cubes. -- Evidence is VIEWER-6 and the layout tests in `uitests/viewer.spec.mjs`. +- Existing default Cubes, Files navigation and Edit/Preview behavior remain; Slice is the additional main workspace and retains current selection, camera and draft. +- Existing draft, composition, phone and disclosure checks continue to pass alongside Slice tests. ### REQ-ThreeMDViewer-004 @@ -78,3 +77,31 @@ Acceptance Criteria: - Zoom stays between 0.5 and 2 in both views. Fit restores the default matched pose (native yaw -0.6 / web yaw 0.6, pitch 0.35), zoom 1 and zero pan. The native CPU cube/ASCII projection, live GPU camera and picking all honor the same orbit and pan. - Shared asymmetric fixture receipts compare camera bases and screen projections across native and browser views, including pole crossings, upside-down and panned cameras. Picking chooses the nearest cube after those movements and camera changes reuse geometry. Mac native regressions and browser Chromium/WebKit regressions cover the controls. - Keep native painting, stroke freezing, CPU/export budgets and the browser one-draw cube mesh, colors, axes and bounded grid behavior. Keep app and viewer specifications and human intent synchronized. Sparse-world Explore, storage formats, parser APIs, package releases and trust policies remain outside this camera change. + +### REQ-ThreeMDViewer-008 + +The browser SHALL offer a Sculpt-style Slice workspace that edits bounded character grids in the current document, preserves the surrounding source, and produces the same supported cell edits as Sculpt. + +Acceptance Criteria: + +- Add Slice beside Edit, Preview and Cubes while keeping Cubes as the default. Slice presents selectable thumbnails, a large editable grid, current one-based X/Y and slice coordinates, an interactive live 3D reference, and Expand back to Cubes. Selection and camera survive view switches; the reference reuses the existing WebGL context. +- Draw, Erase and Fill use the native palette # @ * + o x : = - and period for erased cells. Square brushes of size 1, 3 and 5 clip to the grid. Fast pointer movement follows the same integer line interpolation as SculptureWorkspace, with no gaps. Fill uses four-neighbor connectivity on the selected slice and ignores brush size. +- A drag is one undo step; no-op edits add no history. Undo and redo restore exact source and synchronize the grid and reference. Source typing and visual edits use coherent history, retained with each draft and shared by linked file/entry views. A new edit clears redo. History is bounded to 100 entries per draft and an 8 MiB collection budget without dropping the current source. Pointer release, cancel, lost capture or navigation finish the current accepted stroke and prevent late writes into another document. +- Arrow keys move the selected cell within bounds; Space applies the current tool. Explicit X/Y controls and Apply support precise keyboard editing. Grid zoom offers Fit, 2x, 4x, 8x and 16x with internal scrolling. Show previous slice overlays occupied cells only behind empty current cells, is unavailable on the first slice, and never mutates source. +- Eligible documents contain complete rectangular fenced ASCII grids with common dimensions, the native palette and period/space empty cells. Empty grids remain editable. Keep the viewer limits of 64 columns, 64 rows, 4000 occupied cells and 12 distinct render glyphs; visual editing additionally limits eligible documents to 256 slices and 1.5 MiB of source. Prose, invalid, ragged, tabbed, unsupported-glyph or over-budget documents retain Edit/Preview/Cubes as appropriate and explain why Slice editing is unavailable. A proposed edit that exceeds a limit is rejected without committing a partial transaction or adding undo history. +- Source edits replace only targeted grid characters, preserving frontmatter, plane coordinates, labels, other body content, fence markers and newline style byte for byte. Visual edits immediately participate in Edited markers, source download, kind 2 export, search and packing. They do not write original files, persist browser storage or rewrite a composition profile. +- Slice remains usable at 390x844 and 320x740 with touch targets, visible keyboard focus, named controls, an accessible selected-cell description and no page overflow. The 2D editor works without WebGL2; the reference explains GPU unavailability and preserves edits. The existing camera, file, composition, export and accessibility regressions continue to pass. +- Shared asymmetric edit fixtures verify native/browser Draw, Erase, Fill, clipped brushes, sparse diagonal input and undo/redo against independently specified final cells. Chromium and WebKit tests exercise actual pointer and keyboard flows, exact source preservation, empty grids, history boundaries, composition switching, downloads and phone layout. Evidence distinguishes automated checks, agent visual inspection, local Trust, remote CI and provenance limitations. + +### REQ-ThreeMDViewer-007 + +The viewer and Sculpt volume view SHALL provide matched document-axis rotation constraints and numerical rotation/pan steps alongside the camera sphere. + +Acceptance Criteria: + +- Both volume views show a small sphere with colored X, Y and Z rotation rings and accessible axis buttons. Choosing an axis constrains dragging and step buttons to rotation around that document axis; Free restores unconstrained orbit. +- Three-axis rotation preserves an orthonormal camera orientation and supports Z rotation without changing model cells, slice, Undo, files, or installed geometry. Native and browser use the same document-axis convention, including row Y and plane Z. +- Both views offer an editable rotation step in degrees (default 15 degrees) with minus and plus nudges, and an editable pan step in cells (default 0.25) with directional nudges. Values must be finite and positive; invalid input leaves the current camera unchanged. Fit resets the default pose and pan. +- Tests compare shared asymmetric projection and picking cases including Z rotation, full X/Y/Z turns, negative nudges and exact inverse steps; native live and scalar renderers agree. Camera controls remain usable on narrow screens and have keyboard labels and focus indication. +- Synchronize viewer and Sculpt contracts and intent, record actual current tests, and complete verified lifecycle closure only under Leif’s explicit approval of this new definition. Leif retains PR merge authority. Preserve storage, rendering budgets, parser APIs, releases and trust policy. + From 3dd9cc9759ebf257633eea07a262f099135bc94b Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:04:01 -0600 Subject: [PATCH 28/43] chore(lifecycle): materialize bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference --- .../state.json | 4 ++-- .../verification-attempts.json | 24 +++++++++++++++++++ .../verification.json | 19 +++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json create mode 100644 .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json index 0a2b736..ade4ded 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json @@ -7,11 +7,11 @@ "title": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", "description": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", "kind": "feature", - "state": "implementing", + "state": "verifying", "canonical_applied": true, "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", "created_at": 1791652000, - "updated_at": 1791655366, + "updated_at": 1791655441, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json new file mode 100644 index 0000000..43052d5 --- /dev/null +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json @@ -0,0 +1,24 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1791655435, + "commit": "c86a777aa255ae3f36341ab2b684dc3896f5606c", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] + } + ] +} diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json new file mode 100644 index 0000000..1b696e9 --- /dev/null +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json @@ -0,0 +1,19 @@ +{ + "timestamp": 1791655435, + "commit": "c86a777aa255ae3f36341ab2b684dc3896f5606c", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] +} From 879ea2515e5a5a9e04ab6672228d9013ae4a4d82 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:04:26 -0600 Subject: [PATCH 29/43] chore(lifecycle): record bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference verification --- .../state.json | 2 +- .../verification-attempts.json | 19 +++++++++++++++++++ .../verification.json | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json index ade4ded..51ce99f 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", "created_at": 1791652000, - "updated_at": 1791655441, + "updated_at": 1791655466, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json index 43052d5..3ec3515 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json @@ -19,6 +19,25 @@ "REQ-ThreeMDViewer-003", "REQ-ThreeMDViewer-008" ] + }, + { + "timestamp": 1791655458, + "commit": "3dd9cc9759ebf257633eea07a262f099135bc94b", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] } ] } diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json index 1b696e9..8081d0a 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json @@ -1,6 +1,6 @@ { - "timestamp": 1791655435, - "commit": "c86a777aa255ae3f36341ab2b684dc3896f5606c", + "timestamp": 1791655458, + "commit": "3dd9cc9759ebf257633eea07a262f099135bc94b", "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", From 3dce9ac0825a9f4c931670540e56d60859249901 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:06:32 -0600 Subject: [PATCH 30/43] chore(lifecycle): materialize add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer --- .../state.json | 4 ++-- .../verification-attempts.json | 23 +++++++++++++++++++ .../verification.json | 18 +++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json create mode 100644 .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json index f51262c..fd92ae2 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json @@ -7,11 +7,11 @@ "title": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", "description": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", "kind": "feature", - "state": "implementing", + "state": "verifying", "canonical_applied": true, "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", "created_at": 1791644309, - "updated_at": 1791655390, + "updated_at": 1791655592, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json new file mode 100644 index 0000000..f47116f --- /dev/null +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json @@ -0,0 +1,23 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1791655587, + "commit": "879ea2515e5a5a9e04ab6672228d9013ae4a4d82", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] + } + ] +} diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json new file mode 100644 index 0000000..09c35f8 --- /dev/null +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json @@ -0,0 +1,18 @@ +{ + "timestamp": 1791655587, + "commit": "879ea2515e5a5a9e04ab6672228d9013ae4a4d82", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] +} From df0de61783043c0482fd7214d474110db5e2b068 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:06:52 -0600 Subject: [PATCH 31/43] chore(lifecycle): record add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer verification --- .../state.json | 2 +- .../verification-attempts.json | 18 ++++++++++++++++++ .../verification.json | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json index fd92ae2..e03ca6d 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", "created_at": 1791644309, - "updated_at": 1791655592, + "updated_at": 1791655612, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json index f47116f..b3ce968 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json @@ -18,6 +18,24 @@ "requirement_ids": [ "REQ-ThreeMDViewer-007" ] + }, + { + "timestamp": 1791655607, + "commit": "3dce9ac0825a9f4c931670540e56d60859249901", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] } ] } diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json index 09c35f8..a0f4b03 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json @@ -1,6 +1,6 @@ { - "timestamp": 1791655587, - "commit": "879ea2515e5a5a9e04ab6672228d9013ae4a4d82", + "timestamp": 1791655607, + "commit": "3dce9ac0825a9f4c931670540e56d60859249901", "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", From 8a72e4759bd904ba98d5a5ad72776012a98ce37d Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:07:32 -0600 Subject: [PATCH 32/43] Record Linux parity checks and synchronize current viewer companion requirements --- .../testing.md | 2 +- .../testing.md | 2 +- docs/evidence/viewer-slice/README.md | 3 +- docs/evidence/viewer-slice/linux-ci.log | 1615 +++++++++++++++++ specs/ThreeMDViewer/ThreeMDViewer.spec.md | 4 +- specs/ThreeMDViewer/context.md | 2 +- specs/ThreeMDViewer/requirements.md | 4 +- specs/ThreeMDViewer/tasks.md | 5 +- specs/ThreeMDViewer/testing.md | 5 + 9 files changed, 1633 insertions(+), 9 deletions(-) create mode 100644 docs/evidence/viewer-slice/linux-ci.log diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md index 5739bed..ae615e6 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md @@ -9,7 +9,7 @@ Test each document axis with positive, negative and full-turn rotations, includi ## Execution evidence -Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux and final lifecycle receipts are recorded in docs/evidence/viewer-slice. Source and visual verification are distinct from Leif’s diff review. +Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux CI passed 218 functional tests with 8 existing platform-snapshot skips and no retries; all macOS snapshots passed. Current receipts are in docs/evidence/viewer-slice; final lifecycle receipts are separate. Source and visual verification are distinct from Leif’s diff review. ## Requirement evidence diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md index 0c664a1..947163c 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md @@ -17,7 +17,7 @@ Run the complete viewer suite on macOS and the complete UI suite in the existing ## Execution evidence -Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux and final lifecycle receipts are recorded in docs/evidence/viewer-slice. Source and visual verification are distinct from Leif’s diff review. +Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux CI passed 218 functional tests with 8 existing platform-snapshot skips and no retries; all macOS snapshots passed. Current receipts are in docs/evidence/viewer-slice; final lifecycle receipts are separate. Source and visual verification are distinct from Leif’s diff review. ## Requirement evidence diff --git a/docs/evidence/viewer-slice/README.md b/docs/evidence/viewer-slice/README.md index b510a0c..796b652 100644 --- a/docs/evidence/viewer-slice/README.md +++ b/docs/evidence/viewer-slice/README.md @@ -5,6 +5,7 @@ The browser Slice workspace follows Sculpt’s Draw/Erase/Fill, palette and squa Verified locally on 2026-10-10: - Full macOS Chromium/WebKit UI suite: 226 passed, no skips or retries (`mac-browser.log`). +- Linux CI Chromium/WebKit suite: 218 passed, 8 existing platform-snapshot skips, no retries, in 3.4 minutes (`linux-ci.log`). The first run omitted CI=1 and passed all 218 functional tests but failed eight macOS-only visual snapshot comparisons; the complete rerun used the repository’s unchanged CI policy. All eight snapshots passed in the full macOS run. - Final expanded shared browser fixtures: 4 passed (`browser-fixtures.log`). - Final phone regressions at 390×844 and 320×740: 4 passed (`phone.log`). - Configured native regression selection: 637 tests in 54 suites passed (`native-full.log`), using the existing `--skip deterministicPortableInterchangeFixtures` selection. The previously established release-fixture/version mismatch remains outside this UI change; no new skip was introduced. @@ -17,6 +18,6 @@ Slice preserves raw non-target text, including CRLF, fractional plane positions, The browser’s supported edit profile is complete common rectangular grids up to 64×64, 256 planes, 4000 occupied cells and 1.5 MiB source, with the native palette and dot/space empties. Structural slice actions, volume resizing and browser 3D painting remain subsequent work. Native storage, formats, library APIs, examples, generated browser bundles and releases are unchanged. -Linux, final Trust and lifecycle receipts are recorded after their current runs complete. Actual reviewer identity is agent:codex. Scope and conditional verified closure were directly authorized by Leif; that does not supply a permitted signature or a human diff review. Existing soft unsigned provenance policy remains intact. +Linux CI verification is complete. Final Trust and lifecycle receipts will be recorded after their current runs complete. Actual reviewer identity is agent:codex. Scope and conditional verified closure were directly authorized by Leif; that does not supply a permitted signature or a human diff review. Existing soft unsigned provenance policy remains intact. Implementation commit: `8e9a0c4`. Pinned Trust 1.2.2 / Fledge 1.7.2 passed (`trust-implementation.log`). Actual unsigned agent:codex record and unchanged policy result are in `attestation-implementation.json` and `provenance-implementation.json`; the strict provenance policy fails for the unsigned/unpermitted reviewer, while Trust’s configured soft mode passes with progressive provenance. No policy was changed. diff --git a/docs/evidence/viewer-slice/linux-ci.log b/docs/evidence/viewer-slice/linux-ci.log new file mode 100644 index 0000000..171b153 --- /dev/null +++ b/docs/evidence/viewer-slice/linux-ci.log @@ -0,0 +1,1615 @@ + +Running 226 tests using 2 workers +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /sample.3md HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:02:58] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:00] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:02] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:04] "GET /sample.3md HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:06] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:06] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:06] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:06] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:06] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:06] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:08] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:09] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:09] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:10] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:10] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:15] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:15] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:15] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:19] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:19] "GET /all-examples.json HTTP/1.1" 200 - +·°°°°[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:20] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /viewer.html HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:21] "GET /gallery-data.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:22] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:23] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:27] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:30] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:31] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:32] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:33] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:34] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:36] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:37] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:38] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/theme.js HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:39] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:40] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:41] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:42] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:43] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:44] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:45] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:46] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /viewer.html HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /viewer.html?src=original-document.3md&theme=dark HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:49] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:50] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:51] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:52] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:53] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:54] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:55] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:56] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:03:59] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:03] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:03] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:10] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:11] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /sample.3md HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /assets/tokens.css HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:13] "GET /sample.3md HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /embed-example.html HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:15] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:16] "GET /assets/tokens.css HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:17] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:19] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /sample.3md HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:20] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:21] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:21] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:25] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:25] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:28] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:28] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:29] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:41] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:41] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:41] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:41] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:42] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:42] "GET /index.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:43] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:43] "GET /all-examples.json HTTP/1.1" 200 - +·°° +°°[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:45] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:46] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:47] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:48] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:49] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:50] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:52] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:53] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:54] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:55] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:57] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:58] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:04:59] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /gallery-data.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:01] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:02] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:04] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:05] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:07] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:08] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:10] "GET /gallery-data.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:11] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:12] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /viewer.html HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:13] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:14] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:17] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:17] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:17] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:17] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:18] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:19] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:21] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:23] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:24] "GET /nested-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:25] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:26] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:27] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:30] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:32] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:34] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:36] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /viewer.html?src=original-document.3md&theme=dark HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /binary-samples.json HTTP/1.1" 200 - +··[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:40] "GET /all-examples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:43] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:44] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:44] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:44] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:44] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:44] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:45] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:48] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:49] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:51] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:51] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:51] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:51] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:51] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:52] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:53] "GET /binary-samples.json HTTP/1.1" 200 - +·[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] 127.0.0.1 - - [10/Oct/2026 18:05:54] "GET /all-examples.json HTTP/1.1" 200 - +·· +::notice title=🎭 Playwright Run Summary:: 8 skipped%0A 218 passed (3.4m) + 8 skipped + 218 passed (3.4m) diff --git a/specs/ThreeMDViewer/ThreeMDViewer.spec.md b/specs/ThreeMDViewer/ThreeMDViewer.spec.md index ce21aeb..e44f172 100644 --- a/specs/ThreeMDViewer/ThreeMDViewer.spec.md +++ b/specs/ThreeMDViewer/ThreeMDViewer.spec.md @@ -1,6 +1,6 @@ --- module: ThreeMDViewer -version: 15 +version: 16 status: active files: - web/viewer.html @@ -74,7 +74,7 @@ The `` element stays a text renderer. Decode, composition, linked fold 4. Search opens the plane for the chosen line. 5. Markdown headings become planes. Opened files pack into one text document. Kind 2 download writes uncompressed kind 2. 6. Apple LZFSE is refused. The element stays a text renderer. The library stays free of filesystem and network I/O. -7. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. Orbit SHALL rotate through full horizontal and vertical turns with a continuous camera basis at the poles. Pan mode, Shift-drag, and middle/right-drag SHALL move the view in screen space. Shift-arrow keys SHALL pan the focused canvas. Two-finger touch gestures SHALL pan and pinch to zoom. Wheel zoom SHALL respond proportionally to the gesture. Fit SHALL restore yaw 0.6, pitch 0.35, zoom 1, and zero pan without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The Document disclosure closes after an action, outside click, or Escape; Escape returns focus to its summary. The source download shortcut keeps focus in Edit. GitHub open exposes a busy state, prevents duplicate submits, and recovers its controls even on failure. Zoom is bounded from 0.5 to 2. Camera controls use the canvas dimensions for framing and occupy a separate strip below it. +7. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. Orbit SHALL rotate through full horizontal and vertical turns with a continuous camera basis at the poles. Pan mode, Shift-drag, and middle/right-drag SHALL move the view in screen space. Shift-arrow keys SHALL pan the focused canvas. Two-finger touch gestures SHALL pan and pinch to zoom. Wheel zoom SHALL respond proportionally to the gesture. Fit SHALL restore yaw 0.6, pitch 0.35, zoom 1, and zero pan without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The Document disclosure closes after an action, outside click, or Escape; Escape returns focus to its summary. The source download shortcut keeps focus in Edit. GitHub open exposes a busy state, prevents duplicate submits, and recovers its controls even on failure. Zoom is bounded from 0.5 to 2. Primary camera controls use the canvas dimensions for framing and occupy a separate strip below it. REQ-ThreeMDViewer-007 adds the corner axis sphere and precise movement disclosure. 8. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. Drafts are in memory for the current collection. Download exports the current document and does not write the original file or clear its Edited marker. Opening another collection or refreshing clears these session drafts. Linked entries share their draft with the matching source file. Composition downloads remain exports of the selected document; edits do not rewrite the composition profile. diff --git a/specs/ThreeMDViewer/context.md b/specs/ThreeMDViewer/context.md index 0b248ce..5ceac87 100644 --- a/specs/ThreeMDViewer/context.md +++ b/specs/ThreeMDViewer/context.md @@ -49,7 +49,7 @@ spec: ThreeMDViewer.spec.md ## Current camera parity -Leif explicitly approved full native/browser camera parity and verified closure on 2026-10-10. Both volume canvases now use full yaw/pitch turns, continuous pole bases, session-only screen pan, zoom 0.5...2 and the matched default Fit pose. Native interactive cameras use complete-volume framing while default utility cameras retain historical preview scale. Shared projection/picking fixtures and current screenshots are in `docs/evidence/viewer-camera/`. The X/Y/Z sphere and precise step controls have a separate complete draft; definition approval is pending. +Leif explicitly approved full native/browser camera parity and verified closure on 2026-10-10. Both volume canvases now use full yaw/pitch turns, continuous pole bases, session-only screen pan, zoom 0.5...2 and the matched default Fit pose. Native interactive cameras use complete-volume framing while default utility cameras retain historical preview scale. Shared projection/picking fixtures and current screenshots are in `docs/evidence/viewer-camera/`. Leif subsequently approved the X/Y/Z sphere, precise steps and browser Slice definition together; implementation and current verification are recorded in `docs/evidence/viewer-slice/`. ## Slice and precise camera parity diff --git a/specs/ThreeMDViewer/requirements.md b/specs/ThreeMDViewer/requirements.md index 9119e98..647377c 100644 --- a/specs/ThreeMDViewer/requirements.md +++ b/specs/ThreeMDViewer/requirements.md @@ -12,7 +12,7 @@ spec: ThreeMDViewer.spec.md - **REQ-ThreeMDViewer-001** The viewer page SHALL present files, source, and the live plane view. It SHALL open a public GitHub repo, folder, or file, or a file or folder from this computer. Search SHALL read every opened line and open that plane. Markdown headings SHALL become planes. Opened files SHALL pack into one text document, and that document SHALL download as uncompressed kind 2. The `` element SHALL stay a text renderer. - **REQ-ThreeMDViewer-002** The page SHALL accept a GitHub locator only when the host is `github.com`, `www.github.com`, or `raw.githubusercontent.com`, or when the input is an `owner/repo` name. It SHALL NOT treat those names as a match when they appear only as a substring. A public load SHALL skip `node_modules`, SHALL keep at most 400 files, and SHALL skip a file larger than 1.5 MB. The line index SHALL keep at most 12,000 rows. Apple LZFSE SHALL be refused. The ThreeMD library SHALL stay free of filesystem and network I/O. -- **REQ-ThreeMDViewer-003** The viewer page SHALL show Edit, Preview, and Cubes in one panel. Exactly one of them SHALL be visible. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, and Cubes. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. +- **REQ-ThreeMDViewer-003** The viewer page SHALL show Edit, Preview, Cubes, and Slice in one panel. Exactly one main view SHALL be visible; Slice SHALL include a live 3D reference within its workspace. Cubes SHALL be the default, and the opening document SHALL be a small sculpture whose cubes are inside the window. Files SHALL stay in the column beside that panel. Below 900px, Files and the document SHALL take turns, and the document panel SHALL still switch Edit, Preview, Cubes, and Slice. Choosing Preview SHALL render the live plane view. The workspace SHALL keep infrequent export and conversion actions in the Document disclosure, show insert tools only in Edit, and show the document title in every view. Tabs and the single-row plane outline SHALL provide one tab stop per group, with arrow, Home, and End navigation. File and composition-entry navigation SHALL preserve current edits, caret, and selected plane within the open collection. Edited documents SHALL be identified in every view. Opened files SHALL support filtering and keyboard navigation. Choosing a file or search result on a narrow screen SHALL reveal the document. Search and packing SHALL use current drafts. Failed local opens SHALL preserve the current collection. Explicit document navigation SHALL replace a stale source query with the current document hash. The Slice workspace SHALL preserve the current selected plane, camera and source when entering or leaving the view. - **REQ-ThreeMDViewer-004** The viewer page SHALL NOT offer a render-mode switch and SHALL NOT autoplay. Preview SHALL stay on one plane. Cubes SHALL draw complete, nearly cell-sized cubes with WebGL2, lit glyph-colored fill at 0.5 opacity and visible glyph-colored edges. The selected Z slice SHALL have gold edges at 0.8 opacity while retaining its glyph fill. The background SHALL be rgb(0.065, 0.085, 0.10). X SHALL be the column, Y the text row with row 0 toward the top, and Z the plane index. Orbit, zoom, and slice selection SHALL reuse the installed geometry. Each redraw SHALL use one instanced draw. Orbit SHALL rotate through full horizontal and vertical turns with a continuous camera basis at the poles. Pan mode, Shift-drag, and middle/right-drag SHALL move the view in screen space. Shift-arrow keys SHALL pan the focused canvas. Two-finger touch gestures SHALL pan and pinch to zoom. Wheel zoom SHALL respond proportionally to the gesture. Fit SHALL restore yaw 0.6, pitch 0.35, zoom 1, and zero pan without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The element bundle SHALL stay a text renderer. ## Constraints @@ -24,7 +24,7 @@ spec: ThreeMDViewer.spec.md ## Out of Scope - Parser, CLI, and element behavior. -- Cube painting or erasing into source, 256 cubed volumes, sparse worlds, OBJ export, and Sculpt app changes. +- Browser 3D cube painting, structural slice actions, volume resizing, 256 cubed volumes, sparse worlds and OBJ export. Sculpt changes are limited to the approved volume camera parity scope. - Gallery cards, which stay the curated text set. - Private GitHub repos, remote folder indexes beyond the public git tree, and Apple LZFSE. diff --git a/specs/ThreeMDViewer/tasks.md b/specs/ThreeMDViewer/tasks.md index a649e5e..eb7168a 100644 --- a/specs/ThreeMDViewer/tasks.md +++ b/specs/ThreeMDViewer/tasks.md @@ -46,4 +46,7 @@ spec: ThreeMDViewer.spec.md - [x] Match Sculpt and viewer full orbit through both poles with camera-only pan and proportional zoom. - [x] Add shared asymmetric native/browser projection and picking fixtures. - [x] Finish current cross-platform verification and lifecycle closure for the camera scope. -- [ ] Await definition approval for the separate axis gizmo and numeric precision controls. +- [x] Implement the approved matching axis gizmo and numeric precision controls. +- [x] Add the approved browser Slice workspace and shared native/browser edit fixtures. +- [x] Verify current macOS browser, Linux CI, native and pinned Trust checks. +- [ ] Complete current Slice and precise-axis lifecycle closure. diff --git a/specs/ThreeMDViewer/testing.md b/specs/ThreeMDViewer/testing.md index a67efed..bd23e9c 100644 --- a/specs/ThreeMDViewer/testing.md +++ b/specs/ThreeMDViewer/testing.md @@ -63,3 +63,8 @@ Slice uses the native character palette `#@*+ox:=-`, Draw/Erase square brushes 1 History is shared with source typing and attached to each draft state, including linked entries. It retains at most 100 snapshots per draft and 8 MiB across the current collection; no-op strokes add no entry. Pointer up, cancellation, lost capture and navigation finish the accepted transaction. Thumbnails, one-based coordinates, keyboard arrows/Space, explicit cell Apply, previous-slice ghosts and Fit/2x/4x/8x/16x grid zoom use the same state. The live reference reparents the existing WebGL canvas rather than allocating another context; 2D editing remains available without WebGL. Phone layouts scroll inside Slice with full-size touch targets. The volume camera shows colored X/Y/Z rings and Free/X/Y/Z constraints. A normalized quaternion composes document-axis rotation with continuous free orbit. Numerical rotation defaults to 15 degrees and pan to 0.25 cells, accepting only finite positive steps. Fit restores the default orientation and zero pan. Shared independent matrix-reference cases cover three-axis projection and picking; shared edit cases run through actual Sculpt workspaces and browser pointer gestures. + + +## Current approved Slice and precise-axis verification + +2026-10-10: complete macOS UI 226 passed without skips or retries; Linux CI UI 218 passed with 8 existing platform-snapshot skips and no retries; configured native suite 637 passed and final parity selection 11 passed. Shared fixtures compare native workspace edits and actual browser gestures against independent expected rows and camera matrices. Logs and actual UI screenshots are in `docs/evidence/viewer-slice/`. Pinned Trust passed for implementation commit `8e9a0c4`; final archive-tip verification remains separate. Actual unsigned agent:codex provenance is recorded and does not satisfy the unchanged strict permitted-signature/reviewer policy. From 0f32c12ab9f932c428f319d0bf38a02f3cf6f1da Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:08:04 -0600 Subject: [PATCH 33/43] chore(lifecycle): materialize bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference --- .../state.json | 2 +- .../verification-attempts.json | 19 +++++++++++++++++++ .../verification.json | 8 ++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json index 51ce99f..5e11ac9 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", "created_at": 1791652000, - "updated_at": 1791655466, + "updated_at": 1791655684, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json index 3ec3515..1112062 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json @@ -38,6 +38,25 @@ "REQ-ThreeMDViewer-003", "REQ-ThreeMDViewer-008" ] + }, + { + "timestamp": 1791655680, + "commit": "8a72e4759bd904ba98d5a5ad72776012a98ce37d", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] } ] } diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json index 8081d0a..0d5ed46 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json @@ -1,9 +1,9 @@ { - "timestamp": 1791655458, - "commit": "3dd9cc9759ebf257633eea07a262f099135bc94b", + "timestamp": 1791655680, + "commit": "8a72e4759bd904ba98d5a5ad72776012a98ce37d", "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", - "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", - "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", "passed": true, "commands": [ { From 6e8d0bb72dec11684d501cf5cbdc25b2f276b853 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:08:24 -0600 Subject: [PATCH 34/43] chore(lifecycle): record bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference verification --- .../state.json | 2 +- .../verification-attempts.json | 19 +++++++++++++++++++ .../verification.json | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json index 5e11ac9..eb0f612 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", "created_at": 1791652000, - "updated_at": 1791655684, + "updated_at": 1791655704, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json index 1112062..5ca0f4c 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json @@ -57,6 +57,25 @@ "REQ-ThreeMDViewer-003", "REQ-ThreeMDViewer-008" ] + }, + { + "timestamp": 1791655699, + "commit": "0f32c12ab9f932c428f319d0bf38a02f3cf6f1da", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] } ] } diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json index 0d5ed46..d95fd92 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json +++ b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json @@ -1,6 +1,6 @@ { - "timestamp": 1791655680, - "commit": "8a72e4759bd904ba98d5a5ad72776012a98ce37d", + "timestamp": 1791655699, + "commit": "0f32c12ab9f932c428f319d0bf38a02f3cf6f1da", "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", From 06a806db5100c0b3c0807819bc7c10ad453351e5 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:10:50 -0600 Subject: [PATCH 35/43] Archive verified Sculpt-style browser Slice change --- .../accepted-state.json | 45 +++ .../approvals.json | 7 + .../change.md | 2 +- .../context.md | 0 .../deltas/ThreeMDViewer.md | 0 .../design.md | 0 .../docs.md | 0 .../finalization.json | 12 + .../lesson-bundle.md | 84 +++++ .../plan.md | 0 .../requirements.md | 0 .../research.md | 0 .../review-attempts.json | 21 ++ .../review.json | 16 + .../state.json | 4 +- .../tasks.md | 0 .../testing.md | 0 .../verification-attempts.json | 346 ++++++++++++++++++ .../verification.json | 265 ++++++++++++++ .../verification-attempts.json | 81 ---- .../verification.json | 19 - 21 files changed, 799 insertions(+), 103 deletions(-) create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/accepted-state.json rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/approvals.json (89%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/change.md (98%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/context.md (100%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/deltas/ThreeMDViewer.md (100%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/design.md (100%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/docs.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/finalization.json create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/lesson-bundle.md rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/plan.md (100%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/requirements.md (100%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/research.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review-attempts.json create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review.json rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/state.json (97%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/tasks.md (100%) rename .specsync/{changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference => archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference}/testing.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json create mode 100644 .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json delete mode 100644 .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json delete mode 100644 .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/accepted-state.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/accepted-state.json new file mode 100644 index 0000000..1ccd903 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/accepted-state.json @@ -0,0 +1,45 @@ +{ + "schema_version": 1, + "workflow_version": 2, + "workflow_origin_version": 2, + "id": "bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "slug": "bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "title": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", + "description": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", + "kind": "feature", + "state": "accepted", + "canonical_applied": true, + "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", + "created_at": 1791652000, + "updated_at": 1791655783, + "affected_specs": [ + "ThreeMDViewer" + ], + "affected_paths": [ + "web/viewer.html", + "uitests/viewer.spec.mjs", + "apps/sculpt/Tests/RookAppTests/SculptureWorkspaceTests.swift", + "docs/evidence/viewer-slice", + "hi/tools.md" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "Add a Sculpt-style Slice workspace with thumbnails, an editable grid, Draw Erase Fill, the native glyph palette, square brush sizes 1 3 5, gap-free strokes, one undo step per drag, redo, keyboard cell controls, previous-slice overlay, grid zoom and live 3D reference; preserve exact source outside edited grid cells and existing drafts downloads and camera behavior; verify shared native/browser edit fixtures and Chromium WebKit desktop phone interaction checks." + ], + "selected_artifacts": [ + "context", + "requirements", + "plan", + "tasks", + "testing", + "docs", + "design", + "research" + ], + "dependencies": [], + "answers": { + "architecture_risk": "yes", + "public_contract": "yes" + } +} diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/approvals.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/approvals.json similarity index 89% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/approvals.json rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/approvals.json index 05255a4..14d0aaf 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/approvals.json +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/approvals.json @@ -37,6 +37,13 @@ "approved_delta_digests": { "ThreeMDViewer": "5da4b8303d240d01a794275be3f3e806b949aef6525dccdd19e2c4cf9b9cca9e" } + }, + { + "gate": "finalization", + "actor": "specsync:finalization", + "timestamp": 1791655783, + "digest": "81add2ee28a6a48eb29571e64c50b2f5a19e4e2c9f085554f3a00a71a731a620", + "note": "Same-PR finalization closing digest" } ], "reopenings": [] diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/change.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/change.md similarity index 98% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/change.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/change.md index 43fdf00..c30006f 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/change.md +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/change.md @@ -1,6 +1,6 @@ --- id: bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference -state: implementing +state: archived type: feature base_commit: fa61988c163583e5e03cbe00f301b036f37dd7b2 --- diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/context.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/context.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/context.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/context.md diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/deltas/ThreeMDViewer.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/deltas/ThreeMDViewer.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/deltas/ThreeMDViewer.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/deltas/ThreeMDViewer.md diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/design.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/design.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/design.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/design.md diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/docs.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/docs.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/docs.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/docs.md diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/finalization.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/finalization.json new file mode 100644 index 0000000..5e4ce8f --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/finalization.json @@ -0,0 +1,12 @@ +{ + "schema_version": 2, + "change_id": "bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "implementation_commit": "6e8d0bb72dec11684d501cf5cbdc25b2f276b853", + "implementation_tree": "87451f2cfbbdf4b72ad4e767612aa45e91478c81", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "closing_digest": "81add2ee28a6a48eb29571e64c50b2f5a19e4e2c9f085554f3a00a71a731a620", + "review_digest": "855b061f32615f8397bb99951a89b1b7d0a691fc1508e574abe41b268a242ca6", + "finalization_digest": "0caf17781aef4d755beecc9b6930d254942651a5365545cae8df19c5ed4bee94", + "timestamp": 1791655783 +} diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/lesson-bundle.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/lesson-bundle.md new file mode 100644 index 0000000..8f091e4 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/lesson-bundle.md @@ -0,0 +1,84 @@ +# Lesson bundle — bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference + +Material for folding this change's lessons into the affected specs' `context.md`. +Synthesise from what actually happened below; do not restate the change description. + +## What this change was + +- **Title**: Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference +- **Kind**: Feature +- **Specs**: ThreeMDViewer +- **Paths**: web/viewer.html, uitests/viewer.spec.mjs, apps/sculpt/Tests/RookAppTests/SculptureWorkspaceTests.swift, docs/evidence/viewer-slice, hi/tools.md +- **Acceptance**: Add a Sculpt-style Slice workspace with thumbnails, an editable grid, Draw Erase Fill, the native glyph palette, square brush sizes 1 3 5, gap-free strokes, one undo step per drag, redo, keyboard cell controls, previous-slice overlay, grid zoom and live 3D reference; preserve exact source outside edited grid cells and existing drafts downloads and camera behavior; verify shared native/browser edit fixtures and Chromium WebKit desktop phone interaction checks. + +## Evidence + +- Verification commit: `6e8d0bb72dec11684d501cf5cbdc25b2f276b853` +- Base commit: `fa61988c163583e5e03cbe00f301b036f37dd7b2` +- Verified by: `specsync check --spec ThreeMDViewer --strict` + +## From the change's context.md + +# Context + +Leif asked to keep making the browser as good as Sculpt.3md after showing the native Slice workspace and hearing the current camera/editor distinction. This definition ports the central slice-authoring loop. The current viewer and camera changes are archived in PR 93; the new feature is an unapproved definition, not a retroactive expansion of those records. + +Sources of truth are SculptureEditor.sliceWorkspace/drawingTools, LayerGrid, SculptureWorkspace.paint/line/floodFill/undo/redo and Sculpture.palette. The screenshot shows a 9 by 7 scene with five slices, a teal selected cell and a small 3D reference. Native behavior is reused as the oracle through shared fixtures rather than reimplemented in the native app. + +The page owns exact source, parsed document, active file/entry drafts and the single GPU stage. Native tests receive an additive fixture assertion in their existing workspace test file. Library, parser, bundles, format, releases and native editing behavior stay unchanged. X/Y/Z camera controls have a separate complete draft; neither definition is approved yet. Leif retains merge authority. Actual implementation/review actors are agent:codex, never a different agent or an independent human. + +## From the change's design.md + +# Slice workspace design + +Use the supplied Sculpt screenshot as the visual reference and the current CorvidLabs tokens as the browser identity. The main hierarchy is document title, view selector, Slice canvas and tools. The editable grid gets the largest area; the small reference answers where the selected slice sits in the volume. No new page theme or decorative cards. + +Color uses existing paper/ink/surface/hairline/accent tokens, with the fixed cube background #11161a, teal cell selection near #39cbbb, quieter previous-layer glyphs and gold selected-slice cube edges #ffca70. Schibsted Grotesk remains the UI face; Spline Sans Mono serves grid glyphs and source. Browser light/dark themes remain supported. + +Desktop arrangement inside the existing document panel: + +```text +Document title Edited +Edit Preview Cubes Slice +Slices Slice 1 X 7 Y 4 +[thumb] 1 Fit 2x 4x 8x 16x 3D reference Expand +[thumb] 2 +----------------+ [current GPU stage] +[thumb] 3 | editable cells | Draw Erase Fill +[thumb] 4 | | # @ * + o x : = - +[thumb] 5 +----------------+ Size 1 3 5 +9 x 7 cells Show previous slice Selected cell / Apply + keyboard hint Undo Redo +``` + +Files remain the existing outer navigation. Slice thumbnails are compact inner navigation; on phones they become a horizontal scroll strip. The reference and tools flow below the grid at narrow widths, with the reference collapsible so it does not crowd drawing. Grid zoom scrolls inside the editor; it never widens the page. Tools keep large touch targets, pressed state and visible focus. One grid focus target plus coordinate controls avoids thousands of cell tab stops. + +The subject-specific decision is the glyph grid beside its volumetric context. Review against the screenshot: no hero content, new gradients, overlaid toolbars or generic dashboard cards. Expand moves the same GPU view back to Cubes; edits and camera are preserved. + +## From the change's testing.md + +# Verification + +Shared fixtures under docs/evidence/viewer-slice state initial rectangular native-compatible cells, tool/glyph/size, integer sampled path, selected slice and independently written final rows. Include an asymmetric 9x7x5 case, horizontal/diagonal strokes, repeated points, starts on unchanged cells, size-3/5 corner clipping, erase, four-neighbor fill without crossing diagonals or slice boundaries, no-op fill, and undo/redo. Native SculptureWorkspaceTests run the real workspace; browser tests use actual pointer/key actions. + +Exact-source cases include frontmatter, distinct z positions and labels, body prose around a closed fence, CRLF, space/period empties, and another untouched plane. Require exact non-target bytes after drawing and exact restoration after undo. Invalid/ragged/tabbed/unsupported grids and all budget boundaries keep their source. Empty native-compatible grids must enter Slice and accept drawing. + +History checks mix source typing, insert tools, grid strokes and undo/redo; switch between two files and linked entry/file views; use canceled/lost pointers; exercise trimming and redo invalidation; export/search/pack during pending redraw. No late event may write into a newly activated document. Source download and kind 2 decoding must contain the final edit. + +Chromium/WebKit checks cover desktop and 390x844/320x740 layouts, primary touch drawing, keyboard cell movement and Space, explicit X/Y validation, every zoom option and previous-slice visibility. Require internal grid scrolling, visible controls and meaningful accessibility names. GPU-unavailable Slice editing remains usable. Existing one-context, no camera-only geometry upload, nearest picking and pole-crossing tests run unchanged. + +Run the complete viewer suite on macOS and the complete UI suite in the existing Linux Playwright environment. Run the focused native workspace fixture selection and broaden native tests only if behavior or failures warrant it. Run strict root and nested app specs with full configured coverage, root/native Hi and pinned Trust 1.2.2 with Fledge 1.7.2. Record actual actor, tested source commit, retries/skips and unchanged provenance limits. Actual execution evidence is recorded under docs/evidence/viewer-slice. No independent human review or permitted signature is claimed. + +## Execution evidence + +Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux CI passed 218 functional tests with 8 existing platform-snapshot skips and no retries; all macOS snapshots passed. Current receipts are in docs/evidence/viewer-slice; final lifecycle receipts are separate. Source and visual verification are distinct from Leif’s diff review. + +## Requirement evidence + +| ID | Canonical | Evidence | +| --- | --- | --- | +| REQ-ThreeMDViewer-003 | REQ-ThreeMDViewer-003 | Actual four-view layout in web/viewer.html; full Chromium/WebKit viewer regressions and desktop/phone screenshots in docs/evidence/viewer-slice. | +| REQ-ThreeMDViewer-008 | REQ-ThreeMDViewer-008 | Shared slice-parity.json cases run by browser pointer gestures and native browserSliceFixturesMatchNativeWorkspaceToolsAndWholeStrokeHistory. Source preservation, bounded history, navigation, keyboard, downloads, GPU refusal and phone tests pass; actual logs are in docs/evidence/viewer-slice. | + +## Where these lessons go + +- `specs/ThreeMDViewer/context.md` diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/plan.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/plan.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/plan.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/plan.md diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/requirements.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/requirements.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/requirements.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/requirements.md diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/research.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/research.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/research.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/research.md diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review-attempts.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review-attempts.json new file mode 100644 index 0000000..85c4489 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review-attempts.json @@ -0,0 +1,21 @@ +{ + "schema_version": 1, + "reviews": [ + { + "schema_version": 2, + "change_id": "bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "reviewer": "agent:codex", + "provenance": { + "schema_version": 1, + "provider": "github_actions_check", + "required_check": "SpecSync scoped review" + }, + "verdict": "pass", + "implementation_commit": "6e8d0bb72dec11684d501cf5cbdc25b2f276b853", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "timestamp": 1791655744 + } + ] +} diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review.json new file mode 100644 index 0000000..b83a197 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/review.json @@ -0,0 +1,16 @@ +{ + "schema_version": 2, + "change_id": "bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "reviewer": "agent:codex", + "provenance": { + "schema_version": 1, + "provider": "github_actions_check", + "required_check": "SpecSync scoped review" + }, + "verdict": "pass", + "implementation_commit": "6e8d0bb72dec11684d501cf5cbdc25b2f276b853", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "timestamp": 1791655744 +} diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json similarity index 97% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json index eb0f612..ce947dc 100644 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/state.json @@ -7,11 +7,11 @@ "title": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", "description": "Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference", "kind": "feature", - "state": "verifying", + "state": "archived", "canonical_applied": true, "base_commit": "fa61988c163583e5e03cbe00f301b036f37dd7b2", "created_at": 1791652000, - "updated_at": 1791655704, + "updated_at": 1791655837, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/tasks.md diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md similarity index 100% rename from .specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md rename to .specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/testing.md diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json new file mode 100644 index 0000000..da1fc9f --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json @@ -0,0 +1,346 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1791655435, + "commit": "c86a777aa255ae3f36341ab2b684dc3896f5606c", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] + }, + { + "timestamp": 1791655458, + "commit": "3dd9cc9759ebf257633eea07a262f099135bc94b", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] + }, + { + "timestamp": 1791655680, + "commit": "8a72e4759bd904ba98d5a5ad72776012a98ce37d", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] + }, + { + "timestamp": 1791655699, + "commit": "0f32c12ab9f932c428f319d0bf38a02f3cf6f1da", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] + }, + { + "timestamp": 1791655699, + "commit": "6e8d0bb72dec11684d501cf5cbdc25b2f276b853", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "acceptance_input_digest": "7d9ae9868a12971e4916906777f48079ba9be68815774ac81be3530a50a39d7d", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureWorkspaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f420db050af7dea627b63e3b33e113377e3919b69d24b7d4e5a97a6bcd06c681", + "entry_digest": "997ec23ca0eacd6cd532071f3da63de1da66eb5a0f11ba6902520e84b68c637b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "6e52461b16415b74502ade3fb4a9296404661b2d8b9daeb46ccb0ef6236e14f3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "13d95dffe97a3c30e9dee6f1efcb54e4a4488ea752cf0fd4e5b29f65a060d188", + "entry_digest": "b9bc66178406fb257aa5f3e4877d5d0321add9985f5c3007a834044836661d6c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/attestation-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "468b5420dfa05a8dc8197da78f3e655f1958010dfbd7c3f501fdb6600cb9392e", + "entry_digest": "1a5090b3eea320641a477feff6a3f738912ff39e7061f3a02dd5c6366adea4e0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/browser-desktop.png", + "kind": "file", + "mode": 33188, + "payload_digest": "1c0d118ecf45577588d8c38b87bd0e47e64cd754fe5a062bd8cc3c0fa613ded0", + "entry_digest": "1baba7229c0e086399d741f9feaee4b9cc02f660553971c505b66c5790adc626", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/browser-fixtures.log", + "kind": "file", + "mode": 33188, + "payload_digest": "f10d4be8edc27c9a524edcd81e46ee140dd0b4df6d9cdb85ae0140fb4b6635c8", + "entry_digest": "e76d66ef8b3b40781d0204528348e076f0eabbe6cb24bde98bbde1b142e94703", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/browser-phone.png", + "kind": "file", + "mode": 33188, + "payload_digest": "8aff87748688950f14cafc08eb1686f0374928c9802fb3353c817ba43bdec8b4", + "entry_digest": "96a3bcca297f2d2e33fb2b160493447090f34abf38307903a35a143ba4b2802d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/linux-ci.log", + "kind": "file", + "mode": 33188, + "payload_digest": "38881c05504ec22f137a00375d44dbf1be2b0de44179cdd2c1fbfe522d447911", + "entry_digest": "545f9effeb5f9152d2d3a8b00b1ccd73fd14a84a80ed61cc4ab2631dae0e0b6d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/mac-browser.log", + "kind": "file", + "mode": 33188, + "payload_digest": "8ebaa89f01dd7d5788af9c59c56c8b9c3ff95e49b1da0e03650d668d1b438238", + "entry_digest": "a27a45c3fe71298b77664fc463109ead0c736995273d468694b29b4cb4dfe877", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/native-full.log", + "kind": "file", + "mode": 33188, + "payload_digest": "b9e5a3a50d6312dc11270f7f9301d866e93f68a47564fce94561defa120283fd", + "entry_digest": "6f297fd464f56f2d3b13a8cd35833a13eea22a06e76c651e272674021d61aaec", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/native-parity.log", + "kind": "file", + "mode": 33188, + "payload_digest": "bcc8b1c69e429ffad87ee12c09e236ec8fd294c578ae6f490d8e956b26b4b2ee", + "entry_digest": "667d6ed3703135b5b3d6e506b2260b74571af18643bb88d1e90c26e6a83bd1ba", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/phone.log", + "kind": "file", + "mode": 33188, + "payload_digest": "d1403a073d5817356c3768ed70aa4e1b5dbc71f71da444bef8fbe9a2d64ff98d", + "entry_digest": "b31bf683f4d3247f6a8c7a6f0a53ea82cbfa84cef0aedb1bad1c9ba7fcd594db", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/provenance-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "da4afbc0b7f1c965477d18c3695e3490cc9702a66b64dd21322d5888ba3672a4", + "entry_digest": "cd75a22b45046443d0af903924a889ce6fbb35717ab7fa5715e34e1fa2a762a4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/sculpt-axis.png", + "kind": "file", + "mode": 33188, + "payload_digest": "e2e207fd6f7e300bf39da0b9d46351f778de6c80e1899292dc2ae528474c818b", + "entry_digest": "05b92d61249cd8588ead868c6cb6ce9b19a1bed90031efdf746e02d5be461baf", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/slice-parity.json", + "kind": "file", + "mode": 33188, + "payload_digest": "e62169ce9cebe521a5cdb0e202c522010d38875c0968d5906e0c8244224b0bbb", + "entry_digest": "3b5d98993c5c88fee47ca5302a6ed1357a3fdacd833f8d7e875a3d1e5b2a2ced", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/trust-implementation.log", + "kind": "file", + "mode": 33188, + "payload_digest": "263cde4e72f922ab16278ece04a6d90178b08afbf6012c6fb7b3d58a3914f236", + "entry_digest": "ea4a45ca2723e4279d40d76807713cbebf38630c22b8cf4c7a9932e030eb42f4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "hi/tools.md", + "kind": "file", + "mode": 33188, + "payload_digest": "cd530f076ed449b2dcd994f9178fcb104f4460e44a12042200b42bf6ca6d6306", + "entry_digest": "a13f216eb32a3671d7563024082ab76eb471bdd7a2ddb3c3398b672b05354a70", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/ThreeMDViewer/ThreeMDViewer.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3b3b09952c692c501a98d6520fb8a82f5126ab9b05d64f6634b50cbae3620ae6", + "entry_digest": "64224b139df2b01fdd0db61c4817d9a836030dbf2667bda60529f6a61be627b4", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a0011f2d32b7dce6370e015fefcf09acbcf52578e82a97e56def17e0e0fbed52", + "entry_digest": "e020a4426da69e6b24dd3025c95afd9a88cf073bca235f86ad9104e1de81c7f7", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96612855952a65a5e6b623e2b5d21e9dd8f4ea88c92c0e8ef392e3b826b81f94", + "entry_digest": "5caf30173677b31dcf1119406f03f7dd5a1721487ef58ceacb8d22ed07244d4d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4b0a856509eb4b4c0c875e4b74844c45ce162acf255ce69bf88f86d82feae603", + "entry_digest": "3767a753d3d8c88a88e61820f68b82317f5cd533b57cec5ddc798c7d33ef2656", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e224b1bc77ea1679aa4cbd34f182846717be905bec43bff555d19f0ba5f75b15", + "entry_digest": "fee23d7cfc7097bb6cda3f52a2a0efd8ae2030ec4c32059529bccb53252bc7e1", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "uitests/viewer.spec.mjs", + "kind": "file", + "mode": 33188, + "payload_digest": "52dd2553472620fd956815792cb22c70980c8d70ea4563eac487ec5eb4f28093", + "entry_digest": "05c24eeea687cd37e72eaa5382b93877334fb1cb53ab1b80babe625a09d0393b", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "web/viewer.html", + "kind": "file", + "mode": 33188, + "payload_digest": "457af08a02075688bdec1285f820bd6e6ff48e54c392a6239d3a0519a21197b2", + "entry_digest": "91188b507e047ae68fe1e96a1980f5b33206532a2cabafec98e7d7883e0b70e4", + "owners": [ + "ThreeMDViewer" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] + } + ] +} diff --git a/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json new file mode 100644 index 0000000..c0ca5d9 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json @@ -0,0 +1,265 @@ +{ + "timestamp": 1791655699, + "commit": "6e8d0bb72dec11684d501cf5cbdc25b2f276b853", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "acceptance_input_digest": "7d9ae9868a12971e4916906777f48079ba9be68815774ac81be3530a50a39d7d", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureWorkspaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f420db050af7dea627b63e3b33e113377e3919b69d24b7d4e5a97a6bcd06c681", + "entry_digest": "997ec23ca0eacd6cd532071f3da63de1da66eb5a0f11ba6902520e84b68c637b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "6e52461b16415b74502ade3fb4a9296404661b2d8b9daeb46ccb0ef6236e14f3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "13d95dffe97a3c30e9dee6f1efcb54e4a4488ea752cf0fd4e5b29f65a060d188", + "entry_digest": "b9bc66178406fb257aa5f3e4877d5d0321add9985f5c3007a834044836661d6c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/attestation-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "468b5420dfa05a8dc8197da78f3e655f1958010dfbd7c3f501fdb6600cb9392e", + "entry_digest": "1a5090b3eea320641a477feff6a3f738912ff39e7061f3a02dd5c6366adea4e0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/browser-desktop.png", + "kind": "file", + "mode": 33188, + "payload_digest": "1c0d118ecf45577588d8c38b87bd0e47e64cd754fe5a062bd8cc3c0fa613ded0", + "entry_digest": "1baba7229c0e086399d741f9feaee4b9cc02f660553971c505b66c5790adc626", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/browser-fixtures.log", + "kind": "file", + "mode": 33188, + "payload_digest": "f10d4be8edc27c9a524edcd81e46ee140dd0b4df6d9cdb85ae0140fb4b6635c8", + "entry_digest": "e76d66ef8b3b40781d0204528348e076f0eabbe6cb24bde98bbde1b142e94703", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/browser-phone.png", + "kind": "file", + "mode": 33188, + "payload_digest": "8aff87748688950f14cafc08eb1686f0374928c9802fb3353c817ba43bdec8b4", + "entry_digest": "96a3bcca297f2d2e33fb2b160493447090f34abf38307903a35a143ba4b2802d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/linux-ci.log", + "kind": "file", + "mode": 33188, + "payload_digest": "38881c05504ec22f137a00375d44dbf1be2b0de44179cdd2c1fbfe522d447911", + "entry_digest": "545f9effeb5f9152d2d3a8b00b1ccd73fd14a84a80ed61cc4ab2631dae0e0b6d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/mac-browser.log", + "kind": "file", + "mode": 33188, + "payload_digest": "8ebaa89f01dd7d5788af9c59c56c8b9c3ff95e49b1da0e03650d668d1b438238", + "entry_digest": "a27a45c3fe71298b77664fc463109ead0c736995273d468694b29b4cb4dfe877", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/native-full.log", + "kind": "file", + "mode": 33188, + "payload_digest": "b9e5a3a50d6312dc11270f7f9301d866e93f68a47564fce94561defa120283fd", + "entry_digest": "6f297fd464f56f2d3b13a8cd35833a13eea22a06e76c651e272674021d61aaec", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/native-parity.log", + "kind": "file", + "mode": 33188, + "payload_digest": "bcc8b1c69e429ffad87ee12c09e236ec8fd294c578ae6f490d8e956b26b4b2ee", + "entry_digest": "667d6ed3703135b5b3d6e506b2260b74571af18643bb88d1e90c26e6a83bd1ba", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/phone.log", + "kind": "file", + "mode": 33188, + "payload_digest": "d1403a073d5817356c3768ed70aa4e1b5dbc71f71da444bef8fbe9a2d64ff98d", + "entry_digest": "b31bf683f4d3247f6a8c7a6f0a53ea82cbfa84cef0aedb1bad1c9ba7fcd594db", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/provenance-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "da4afbc0b7f1c965477d18c3695e3490cc9702a66b64dd21322d5888ba3672a4", + "entry_digest": "cd75a22b45046443d0af903924a889ce6fbb35717ab7fa5715e34e1fa2a762a4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/sculpt-axis.png", + "kind": "file", + "mode": 33188, + "payload_digest": "e2e207fd6f7e300bf39da0b9d46351f778de6c80e1899292dc2ae528474c818b", + "entry_digest": "05b92d61249cd8588ead868c6cb6ce9b19a1bed90031efdf746e02d5be461baf", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/slice-parity.json", + "kind": "file", + "mode": 33188, + "payload_digest": "e62169ce9cebe521a5cdb0e202c522010d38875c0968d5906e0c8244224b0bbb", + "entry_digest": "3b5d98993c5c88fee47ca5302a6ed1357a3fdacd833f8d7e875a3d1e5b2a2ced", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-slice/trust-implementation.log", + "kind": "file", + "mode": 33188, + "payload_digest": "263cde4e72f922ab16278ece04a6d90178b08afbf6012c6fb7b3d58a3914f236", + "entry_digest": "ea4a45ca2723e4279d40d76807713cbebf38630c22b8cf4c7a9932e030eb42f4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "hi/tools.md", + "kind": "file", + "mode": 33188, + "payload_digest": "cd530f076ed449b2dcd994f9178fcb104f4460e44a12042200b42bf6ca6d6306", + "entry_digest": "a13f216eb32a3671d7563024082ab76eb471bdd7a2ddb3c3398b672b05354a70", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/ThreeMDViewer/ThreeMDViewer.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3b3b09952c692c501a98d6520fb8a82f5126ab9b05d64f6634b50cbae3620ae6", + "entry_digest": "64224b139df2b01fdd0db61c4817d9a836030dbf2667bda60529f6a61be627b4", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a0011f2d32b7dce6370e015fefcf09acbcf52578e82a97e56def17e0e0fbed52", + "entry_digest": "e020a4426da69e6b24dd3025c95afd9a88cf073bca235f86ad9104e1de81c7f7", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96612855952a65a5e6b623e2b5d21e9dd8f4ea88c92c0e8ef392e3b826b81f94", + "entry_digest": "5caf30173677b31dcf1119406f03f7dd5a1721487ef58ceacb8d22ed07244d4d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4b0a856509eb4b4c0c875e4b74844c45ce162acf255ce69bf88f86d82feae603", + "entry_digest": "3767a753d3d8c88a88e61820f68b82317f5cd533b57cec5ddc798c7d33ef2656", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e224b1bc77ea1679aa4cbd34f182846717be905bec43bff555d19f0ba5f75b15", + "entry_digest": "fee23d7cfc7097bb6cda3f52a2a0efd8ae2030ec4c32059529bccb53252bc7e1", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "uitests/viewer.spec.mjs", + "kind": "file", + "mode": 33188, + "payload_digest": "52dd2553472620fd956815792cb22c70980c8d70ea4563eac487ec5eb4f28093", + "entry_digest": "05c24eeea687cd37e72eaa5382b93877334fb1cb53ab1b80babe625a09d0393b", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "web/viewer.html", + "kind": "file", + "mode": 33188, + "payload_digest": "457af08a02075688bdec1285f820bd6e6ff48e54c392a6239d3a0519a21197b2", + "entry_digest": "91188b507e047ae68fe1e96a1980f5b33206532a2cabafec98e7d7883e0b70e4", + "owners": [ + "ThreeMDViewer" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-003", + "REQ-ThreeMDViewer-008" + ] +} diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json deleted file mode 100644 index 5ca0f4c..0000000 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification-attempts.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "schema_version": 1, - "attempts": [ - { - "timestamp": 1791655435, - "commit": "c86a777aa255ae3f36341ab2b684dc3896f5606c", - "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", - "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", - "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-003", - "REQ-ThreeMDViewer-008" - ] - }, - { - "timestamp": 1791655458, - "commit": "3dd9cc9759ebf257633eea07a262f099135bc94b", - "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", - "execution_digest": "0e3d8c1d90dec9447ee91fa201b2093285994023df80a25e3a96809c7388e494", - "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-003", - "REQ-ThreeMDViewer-008" - ] - }, - { - "timestamp": 1791655680, - "commit": "8a72e4759bd904ba98d5a5ad72776012a98ce37d", - "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", - "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", - "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-003", - "REQ-ThreeMDViewer-008" - ] - }, - { - "timestamp": 1791655699, - "commit": "0f32c12ab9f932c428f319d0bf38a02f3cf6f1da", - "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", - "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", - "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-003", - "REQ-ThreeMDViewer-008" - ] - } - ] -} diff --git a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json b/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json deleted file mode 100644 index d95fd92..0000000 --- a/.specsync/changes/bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/verification.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "timestamp": 1791655699, - "commit": "0f32c12ab9f932c428f319d0bf38a02f3cf6f1da", - "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", - "execution_digest": "8c0c3460123946ea2d50872aab0d8775180c71215745e6aad70feea619be0636", - "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-003", - "REQ-ThreeMDViewer-008" - ] -} From deb44c9222f5ef7593ad19e3786f31aa26d880c9 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:11:09 -0600 Subject: [PATCH 36/43] chore(lifecycle): materialize add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer --- .../state.json | 2 +- .../verification-attempts.json | 18 ++++++++++++++++++ .../verification.json | 8 ++++---- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json index e03ca6d..7166280 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", "created_at": 1791644309, - "updated_at": 1791655612, + "updated_at": 1791655869, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json index b3ce968..48c1c32 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json @@ -36,6 +36,24 @@ "requirement_ids": [ "REQ-ThreeMDViewer-007" ] + }, + { + "timestamp": 1791655864, + "commit": "06a806db5100c0b3c0807819bc7c10ad453351e5", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] } ] } diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json index a0f4b03..ebc664a 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json @@ -1,9 +1,9 @@ { - "timestamp": 1791655607, - "commit": "3dce9ac0825a9f4c931670540e56d60859249901", + "timestamp": 1791655864, + "commit": "06a806db5100c0b3c0807819bc7c10ad453351e5", "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", - "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", - "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", "passed": true, "commands": [ { From 60055f7806a4d46964b766672784be45713e3c3a Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:11:29 -0600 Subject: [PATCH 37/43] chore(lifecycle): record add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer verification --- .../state.json | 2 +- .../verification-attempts.json | 18 ++++++++++++++++++ .../verification.json | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json index 7166280..d3a2fae 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", "created_at": 1791644309, - "updated_at": 1791655869, + "updated_at": 1791655889, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json index 48c1c32..4f72087 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json @@ -54,6 +54,24 @@ "requirement_ids": [ "REQ-ThreeMDViewer-007" ] + }, + { + "timestamp": 1791655884, + "commit": "deb44c9222f5ef7593ad19e3786f31aa26d880c9", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] } ] } diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json index ebc664a..596a5f0 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json +++ b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json @@ -1,6 +1,6 @@ { - "timestamp": 1791655864, - "commit": "06a806db5100c0b3c0807819bc7c10ad453351e5", + "timestamp": 1791655884, + "commit": "deb44c9222f5ef7593ad19e3786f31aa26d880c9", "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", From dab4258541208f8bf6bb5a38f6200a5b348a858e Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:14:12 -0600 Subject: [PATCH 38/43] Archive verified three-axis camera parity and record both closure receipts --- .../accepted-state.json | 55 + .../approvals.json | 7 + .../change.md | 2 +- .../context.md | 0 .../deltas/ThreeMDViewer.md | 0 .../design.md | 0 .../docs.md | 0 .../finalization.json | 12 + .../lesson-bundle.md | 54 + .../plan.md | 0 .../requirements.md | 0 .../research.md | 0 .../review-attempts.json | 21 + .../review.json | 16 + .../state.json | 4 +- .../tasks.md | 0 .../testing.md | 0 .../verification-attempts.json | 1291 +++++++++++++++++ .../verification.json | 1214 ++++++++++++++++ .../verification-attempts.json | 77 - .../verification.json | 18 - docs/evidence/viewer-slice/README.md | 2 +- docs/evidence/viewer-slice/axis-closure.json | 13 + docs/evidence/viewer-slice/slice-closure.json | 13 + specs/ThreeMDViewer/tasks.md | 2 +- specs/ThreeMDViewer/testing.md | 6 +- 26 files changed, 2705 insertions(+), 102 deletions(-) create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/accepted-state.json rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/approvals.json (92%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/change.md (98%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/context.md (100%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/deltas/ThreeMDViewer.md (100%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/design.md (100%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/docs.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/finalization.json create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/lesson-bundle.md rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/plan.md (100%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/requirements.md (100%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/research.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review-attempts.json create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review.json rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/state.json (98%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/tasks.md (100%) rename .specsync/{changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer => archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer}/testing.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json create mode 100644 .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json delete mode 100644 .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json delete mode 100644 .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json create mode 100644 docs/evidence/viewer-slice/axis-closure.json create mode 100644 docs/evidence/viewer-slice/slice-closure.json diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/accepted-state.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/accepted-state.json new file mode 100644 index 0000000..6121faa --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/accepted-state.json @@ -0,0 +1,55 @@ +{ + "schema_version": 1, + "workflow_version": 2, + "workflow_origin_version": 2, + "id": "add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "slug": "add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "title": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", + "description": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", + "kind": "feature", + "state": "accepted", + "canonical_applied": true, + "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", + "created_at": 1791644309, + "updated_at": 1791655945, + "affected_specs": [ + "ThreeMDViewer" + ], + "affected_paths": [ + "web/viewer.html", + "uitests/viewer.spec.mjs", + "hi/tools.md", + "specs/ThreeMDViewer", + "apps/sculpt/Sources/RookSculpture/SculptureProjection.swift", + "apps/sculpt/Sources/RookApp/SculptureViewport.swift", + "apps/sculpt/Sources/RookRendering/SculptureLiveVoxelView.swift", + "apps/sculpt/Sources/RookRendering/SculptureVoxelGeometry.swift", + "apps/sculpt/Tests", + "apps/sculpt/hi", + "apps/sculpt/specs" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "Both volume views show a small sphere with colored X, Y and Z rotation rings and accessible axis buttons. Choosing an axis constrains dragging and step buttons to rotation around that document axis; Free restores unconstrained orbit.", + "Three-axis rotation preserves an orthonormal camera orientation and supports Z rotation without changing model cells, slice, Undo, files, or installed geometry. Native and browser use the same document-axis convention, including row Y and plane Z.", + "Both views offer an editable rotation step in degrees (default 15 degrees) with minus and plus nudges, and an editable pan step in cells (default 0.25) with directional nudges. Values must be finite and positive; invalid input leaves the current camera unchanged. Fit resets the default pose and pan.", + "Tests compare shared asymmetric projection and picking cases including Z rotation, full X/Y/Z turns, negative nudges and exact inverse steps; native live and scalar renderers agree. Camera controls remain usable on narrow screens and have keyboard labels and focus indication.", + "Synchronize viewer and Sculpt contracts and intent, record actual current tests, complete verified lifecycle closure under Leif’s approved PR 93 camera scope, and preserve storage, rendering budgets, parser APIs, releases and trust policy." + ], + "selected_artifacts": [ + "context", + "requirements", + "plan", + "tasks", + "testing", + "docs", + "design", + "research" + ], + "dependencies": [], + "answers": { + "architecture_risk": "yes", + "public_contract": "yes" + } +} diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/approvals.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/approvals.json similarity index 92% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/approvals.json rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/approvals.json index e17866f..7d4ed88 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/approvals.json +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/approvals.json @@ -47,6 +47,13 @@ "approved_delta_digests": { "ThreeMDViewer": "41ce28706a4b04ba3801ad8ef3e98217bdaaf285333d2b519f476919f2767a08" } + }, + { + "gate": "finalization", + "actor": "specsync:finalization", + "timestamp": 1791655945, + "digest": "97d2b14dc39e8ae4fc624f05df89f8af6d26f2dda73159226b4dcd2c0639793d", + "note": "Same-PR finalization closing digest" } ], "reopenings": [] diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/change.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/change.md similarity index 98% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/change.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/change.md index 0820255..d5c8d9c 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/change.md +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/change.md @@ -1,6 +1,6 @@ --- id: add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer -state: implementing +state: archived type: feature base_commit: fefd8316adfff3af8bdb87d26b4a417650540b56 --- diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/context.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/context.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/context.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/context.md diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/deltas/ThreeMDViewer.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/deltas/ThreeMDViewer.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/deltas/ThreeMDViewer.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/deltas/ThreeMDViewer.md diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/design.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/design.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/design.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/design.md diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/docs.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/docs.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/docs.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/docs.md diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/finalization.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/finalization.json new file mode 100644 index 0000000..992b161 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/finalization.json @@ -0,0 +1,12 @@ +{ + "schema_version": 2, + "change_id": "add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "implementation_commit": "60055f7806a4d46964b766672784be45713e3c3a", + "implementation_tree": "9970ef31ab167b4c3429cc3aa17af3651c830918", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "closing_digest": "97d2b14dc39e8ae4fc624f05df89f8af6d26f2dda73159226b4dcd2c0639793d", + "review_digest": "cf186ff11b71dbf0169c2d3aeaa61edefc6e214954bf82620c6ad53d5759d410", + "finalization_digest": "1225a89a0f4a47068497828dd6ef78edf4902c37edde6c9670427d91af38c098", + "timestamp": 1791655945 +} diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/lesson-bundle.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/lesson-bundle.md new file mode 100644 index 0000000..9ceb8b7 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/lesson-bundle.md @@ -0,0 +1,54 @@ +# Lesson bundle — add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer + +Material for folding this change's lessons into the affected specs' `context.md`. +Synthesise from what actually happened below; do not restate the change description. + +## What this change was + +- **Title**: Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer +- **Kind**: Feature +- **Specs**: ThreeMDViewer +- **Paths**: web/viewer.html, uitests/viewer.spec.mjs, hi/tools.md, specs/ThreeMDViewer, apps/sculpt/Sources/RookSculpture/SculptureProjection.swift, apps/sculpt/Sources/RookApp/SculptureViewport.swift, apps/sculpt/Sources/RookRendering/SculptureLiveVoxelView.swift, apps/sculpt/Sources/RookRendering/SculptureVoxelGeometry.swift, apps/sculpt/Tests, apps/sculpt/hi, apps/sculpt/specs +- **Acceptance**: Both volume views show a small sphere with colored X, Y and Z rotation rings and accessible axis buttons. Choosing an axis constrains dragging and step buttons to rotation around that document axis; Free restores unconstrained orbit. +- **Acceptance**: Three-axis rotation preserves an orthonormal camera orientation and supports Z rotation without changing model cells, slice, Undo, files, or installed geometry. Native and browser use the same document-axis convention, including row Y and plane Z. +- **Acceptance**: Both views offer an editable rotation step in degrees (default 15 degrees) with minus and plus nudges, and an editable pan step in cells (default 0.25) with directional nudges. Values must be finite and positive; invalid input leaves the current camera unchanged. Fit resets the default pose and pan. +- **Acceptance**: Tests compare shared asymmetric projection and picking cases including Z rotation, full X/Y/Z turns, negative nudges and exact inverse steps; native live and scalar renderers agree. Camera controls remain usable on narrow screens and have keyboard labels and focus indication. +- **Acceptance**: Synchronize viewer and Sculpt contracts and intent, record actual current tests, complete verified lifecycle closure under Leif’s approved PR 93 camera scope, and preserve storage, rendering budgets, parser APIs, releases and trust policy. + +## Evidence + +- Verification commit: `60055f7806a4d46964b766672784be45713e3c3a` +- Base commit: `fefd8316adfff3af8bdb87d26b4a417650540b56` +- Verified by: `specsync check --spec ThreeMDViewer --strict` + +## From the change's context.md + +# Context + +Leif directly requested a Unity/Godot-style three-axis rotation sphere and precise movement. This is a new addition to the approved full orbit and pan work. The user wants matching native Sculpt and browser behavior. This definition is pending human approval; no implementation, verification, acceptance or archive is claimed. + +## From the change's design.md + +# Design + +Show a compact orientation sphere with red X, green Y and blue Z rings. Click a ring or its labeled axis button to constrain rotation. Free restores ordinary orbit. Degree-step minus/plus buttons rotate only the selected axis; directional buttons use the cell-valued pan step. The controls use native SwiftUI and browser SVG, fit the existing stage design and remain accessible by keyboard. Default steps are 15 degrees and 0.25 cells. Preserve browser controls below the drawing and compact phone layout. + +## From the change's testing.md + +# Testing + +Test each document axis with positive, negative and full-turn rotations, including Z roll and pole crossings. Compare native live, scalar and browser projected points and nearest cube hits. Assert inverse steps restore the same basis, invalid inputs do not mutate the camera, camera adjustments preserve document and geometry, and mobile and keyboard controls stay usable. Run the relevant native and Chromium/WebKit regressions and current trust gate after implementation. + +## Execution evidence + +Implementation commit 8e9a0c4 has 226 passing macOS browser tests, 637 passing configured native tests and 11 passing final native parity tests. Expanded browser fixtures and phone checks each passed 4 cases. Pinned Trust passed; actual unsigned agent:codex provenance was recorded and fails the unchanged permitted-signature/reviewer policy as expected. Linux CI passed 218 functional tests with 8 existing platform-snapshot skips and no retries; all macOS snapshots passed. Current receipts are in docs/evidence/viewer-slice; final lifecycle receipts are separate. Source and visual verification are distinct from Leif’s diff review. + +## Requirement evidence + +| ID | Canonical | Evidence | +| --- | --- | --- | +| REQ-ThreeMDViewer-007 | REQ-ThreeMDViewer-007 | Independent shared camera-parity.json matrix/projection values compared with browser GPU uniforms and nearest picks, native scalar/live basis and picks, full-turn/inverse normalization, ASCII Z picking and mesh installation reuse. Browser precise-input and phone tests pass; native/UI screenshots and logs are in docs/evidence/viewer-slice. | + +## Where these lessons go + +- `specs/ThreeMDViewer/context.md` diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/plan.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/plan.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/plan.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/plan.md diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/requirements.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/requirements.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/requirements.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/requirements.md diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/research.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/research.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/research.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/research.md diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review-attempts.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review-attempts.json new file mode 100644 index 0000000..d834c3a --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review-attempts.json @@ -0,0 +1,21 @@ +{ + "schema_version": 1, + "reviews": [ + { + "schema_version": 2, + "change_id": "add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "reviewer": "agent:codex", + "provenance": { + "schema_version": 1, + "provider": "github_actions_check", + "required_check": "SpecSync scoped review" + }, + "verdict": "pass", + "implementation_commit": "60055f7806a4d46964b766672784be45713e3c3a", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "timestamp": 1791655905 + } + ] +} diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review.json new file mode 100644 index 0000000..748cd37 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/review.json @@ -0,0 +1,16 @@ +{ + "schema_version": 2, + "change_id": "add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "reviewer": "agent:codex", + "provenance": { + "schema_version": 1, + "provider": "github_actions_check", + "required_check": "SpecSync scoped review" + }, + "verdict": "pass", + "implementation_commit": "60055f7806a4d46964b766672784be45713e3c3a", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "timestamp": 1791655905 +} diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json similarity index 98% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json index d3a2fae..306eb1d 100644 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/state.json @@ -7,11 +7,11 @@ "title": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", "description": "Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer", "kind": "feature", - "state": "verifying", + "state": "archived", "canonical_applied": true, "base_commit": "fefd8316adfff3af8bdb87d26b4a417650540b56", "created_at": 1791644309, - "updated_at": 1791655889, + "updated_at": 1791656000, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/tasks.md diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md similarity index 100% rename from .specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md rename to .specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/testing.md diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json new file mode 100644 index 0000000..d4a6a36 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json @@ -0,0 +1,1291 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1791655587, + "commit": "879ea2515e5a5a9e04ab6672228d9013ae4a4d82", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] + }, + { + "timestamp": 1791655607, + "commit": "3dce9ac0825a9f4c931670540e56d60859249901", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", + "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] + }, + { + "timestamp": 1791655864, + "commit": "06a806db5100c0b3c0807819bc7c10ad453351e5", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] + }, + { + "timestamp": 1791655884, + "commit": "deb44c9222f5ef7593ad19e3786f31aa26d880c9", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] + }, + { + "timestamp": 1791655884, + "commit": "60055f7806a4d46964b766672784be45713e3c3a", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "acceptance_input_digest": "75c60a31bc1b305db3d7f15f76d65654d7a80eea3669ed8ed768701654a163a0", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": "apps/sculpt/Sources/RookApp/SculptureViewport.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "8d5ab6c914e03d60dadc58a3e8b6d4f595a261b1e032c46cc0cdbd0597757e45", + "entry_digest": "24442eef4a7215ed811720b44e4f3014ac30df390846447f342ebe7b9d94ff1d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Sources/RookRendering/SculptureLiveVoxelView.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "610272100afb40b290302e64c8cf72544b67f3c2cee3543b292f796531c9750e", + "entry_digest": "210439bcd02c86c1940dbec87538b50db5a465257538913389cb8d82d767fe6c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Sources/RookRendering/SculptureVoxelGeometry.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "24c096ecd359193366e02097643561e28fb3ff422e1fafda1661dbf0f706eb86", + "entry_digest": "b2ff90dc0d60eeb4fdc2983e7c2a13382859ab24164d5d355787aaf98bbe6807", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Sources/RookSculpture/SculptureProjection.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d98745e56609642d7c65369aa67f251d82c3c6089199cd6a2bcc9b1fc928c8d4", + "entry_digest": "22f5d1bb30035cd28eea2c7ed2df463a4ecd679601edeacc7f3e591b9485e267", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "094f12e742e15c4721c78566d011dd8f2dacfdf163828f9b9e12e6dbbfab2764", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/AppearanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "bb460ca170501c02f7e413b1c85c41f0decef55aba4ea735f32c226c36e894e5", + "entry_digest": "ff7f1cf01c86f9e9c1964067854027d5bd8ef674a0894206b189c97a0520df23", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/LayerGridGeometryTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6645f57ab9861bcab490fd53808b6a178c57ae6833e51f4575c31c95f641ef46", + "entry_digest": "abc7fbc1e12be39495e89853bcdaab5cec35152d1d0e48d8c1828c3755e6ded1", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/LayerGridScrollPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1533740a7d0e2347a50bc5ac3ac8ba08037dbc8ac7e3b3c50c022b53f49a765c", + "entry_digest": "a5134e75f1746ab129d9f84012691cc39727df27949a5bce4c6e65ba6d75fa16", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureCanvasPointerTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "2eeb532f40db634a0674a94857aed000224be0526de24fc72a000a2570991883", + "entry_digest": "7e2b1210b7a3eb39e7ebcd1a03d4307a65b2fff0f6181e1ba4be83eb0bc2d5cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureCommandFocusTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "25fb256f29a8991b87e65f09b8caad37711390bf5c7f31da242bbffc13001576", + "entry_digest": "29bbd13e54d55add0704a17c81ad8da3609d7edac595fd6d499105e2e038d9ed", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureCompositionEditorTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "19bb8062f643d384cdee5e768ed856c9d6b7331980d5987164adbb2973027e3f", + "entry_digest": "d733318c97c4ee44e5ae4376cecff5a69567703d854230b84167bbad055aaad2", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureEditorPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ded50853676c0ad3bd625c55d4aaca9769c8e803a04f38ada6c59ae2f49fb095", + "entry_digest": "c75be12388c9fd7c9406e1c524e6d6a339092527fd75575a70927918d22f385d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureExportJobTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "0101679374acf6525820313028313573b49605c068286d1923b7c3d6986ed675", + "entry_digest": "54c858f1e9b793276d3fa7f1b6f2d4249830ab1229f46f3fed4f48e406706616", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureGalleryBrowserTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "59dcb942153a452120eeabe743a971fa707032ed422b24db19876238f3747b6b", + "entry_digest": "2280e89bb09b6dc17012fea72e1a3bda59c7e1d0504039430317ece2ee21a115", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureGraphSaveJobTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "b3c9b2b8bbf482a27161aef9d1ad0bd161353678319ecfc7e833655b6673276c", + "entry_digest": "62c72b46d143f2d230e7e291b4c5c4f5517666e1459fe3181f507c65624db824", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureInsertionDiscoveryTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "18c78362b45c16063ca9cf888e6376ec1bc56872a2e95261257f7fbe7b363f9b", + "entry_digest": "9057cc0eecaffe749a2c592b04ee299624a3a791c8f6e89e9952ca49b3a5187f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureInsertionDraftTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "5efc2d96cdbd08514532647eaa7ca762152f211e99665955f0d081f1478a0d72", + "entry_digest": "c93a1807c59024d7836c48968f603168ae5abf5c18754ce75638beb38999d446", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureInsertionRepairTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6b0fa86e435c43766b7ede2207afc87f460236138c8deaf5b267ac016214a2b1", + "entry_digest": "854eb3a494a8844e8db408b7ea4f42304e8863fea8122776957f6d90da0585c4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedConfinementTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "5b1ec9e5b39bdd52833a9003a62cf63f5c1e88896fce4962120345af7f868849", + "entry_digest": "26d045fd6441c6c932b8497303ba52a107129baedddf46c32d26db5eb2cc8800", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedInsertionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "e8947fbf69251f81c231f8c2936cfdf8558d8240399ab16369c7bee07b78b2de", + "entry_digest": "80649740dee2b7daf7858ad82f009827d83084e20672f2e08768b08df523e563", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d703a36c7eaac77ef95251a924e5f2275a9d1fc2874d053816590d700bb79bb4", + "entry_digest": "bc53d1a4d3030610a40da15cef40c1e4fb4ec8492dc278ac44c285e940ef9797", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedSessionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "afb46a2e240b948ea168b80d3b918090908db29b0e42d14fa17e689862dfb9b0", + "entry_digest": "9de38710e6bcac83215b68343eaa1fdec0e42ca5310fd9899ce9d3edee188e16", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedTestProject.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "c8e07629a75cb25558958ac0ab6de0a383f3962f4f9ef9d53623de8a790251c5", + "entry_digest": "39ca31385c1dc4f6ce086f4edefa4a2fdaf229d7212db2819ec4c0dd886a5db5", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureMeshRevisionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "49950faf4516bdbb9f46d1d6382b12e50f2e1e50cb19b24786b9f24b17ef237d", + "entry_digest": "7ba09620fe295e049072120b8295ff92f7b1637701d435a4a3318a8a9ee6aaee", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculpturePortableInterchangeTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "e33d0ecc55db21dea1e7a22c4c53d08d964bf65cfac4482113228328ba5202e2", + "entry_digest": "bfb5e8f52204376972583ec77fed86a25f79cc65a3d865b68c372b8c6036463c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureReferenceEditorPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6f8f32bafce36b5b50625c5959a3f52b64b1ff87d10200423e4a813e3c15facf", + "entry_digest": "c63963edb0b237f7d076eb1da498122467f07c129f8a294dbb953cec825681d1", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureReferenceSaveSessionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "4f19a8645355e5537b3de91c5d7ce9334cdc20da7cbc334da464b69098c492e5", + "entry_digest": "5fc3bec2792e589ede91c109f0c279256616ca736c99afdcd3d333d20fd53bf7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureSaveJobTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "49808899eefe4ed5e8e0a1ce701749f6d4ef82ff540bff5473c1b5dd634a37c7", + "entry_digest": "3f5101a4313935905c0ce901ce18506f3ebadfa5412b4c770a7c2207dc68c4ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureSharedModelDraftTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "03fc1f9626cd365c84421b581d27b42f842908a09d4cc014939f5dda34cc352f", + "entry_digest": "c4a4e09309acd95d18e227ae25e495f2e44c4ed5f40801e34b347d893297be3f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureSharedModelPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "0e4a7bc7a44619ecd9a001c21e2a29adfdf3b9da9d5a1bfdc7ac0c06a889f336", + "entry_digest": "9b37c492d9734c1aecfde57c7f41568d518020cad3e65e42d3e7d2aa6c9266aa", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureVoxelWorkspaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "085c78d6a0f10a7a63859feb3783dea5a21ff651bd8641618f29bdd0c9c020ab", + "entry_digest": "cb4638941514ef448fce96171889541f28e5cb2fb1d455b0ea8e8b22ac633a30", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureWorkspaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f420db050af7dea627b63e3b33e113377e3919b69d24b7d4e5a97a6bcd06c681", + "entry_digest": "997ec23ca0eacd6cd532071f3da63de1da66eb5a0f11ba6902520e84b68c637b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureWorldEditorTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "51707a0e3b30bdb26826e1f0119b1725d39d735df5e7a3de255fe56e294b7922", + "entry_digest": "5b5b3030f6d5fd568e07c8153d7c155e2ec1a224a582b35f54013f6f567f64e4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SliceGridRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f0d9c2da996754a881e260ac2a7b5b5b81406f5cf97ec857bf92e62edaea9cf0", + "entry_digest": "82df33fc6af7c834ad6b35e2edd38724ca63c5201ee0bc7200ddec753e63757c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookCoreTests/AppAppearanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "96b116fa629f3753d8b42934a811c1428f31636e2856db12bd9f583a9126c368", + "entry_digest": "556583436e1058dc662eef44661aae7333461f13160a1f06a9e1ca9f5fbc006e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/AnimationExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "703d05088f785075738fd195c924270259f2a471566e1b5872881117239fc942", + "entry_digest": "29b0fb1b5fc6a8d6e710a872bf02d19848f68b1d0fdca7a7e06a4e4f2f5042d8", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/CameraParityTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "97c1b35abd129f1f8fc3a2e3fec0ede9b4416b5a0bdd0c53eb55877dca353c6d", + "entry_digest": "7d2c516df02831b4c7701e5d5d3fd31791d99cb6d7b456bd177db175f8fd9c2b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/CubeExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6bff8220f252746e5591956209d228de11b97b8b46e98d0ea09ae13f93c3e324", + "entry_digest": "d76039bb23eb138a74b6e89671c99768c725e12b1760b8582aa64942ddb9665a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/ExampleArtifactTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "affec5f8e6b1f6cb461373dc77d8b1029cafecf2afdb13c1936f15744d055e4b", + "entry_digest": "800fb1804c6303bef36f066056b3cff1fc272c25d83cd619dd9319e463a0b683", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/PreparedVoxelProjectionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "0e828abc9fdfd275524439149a7767457afec885207c9483d64e876e9a4feaf8", + "entry_digest": "af9ffdfd90d0fdaaa3393c432448e3f955318e2754321f66e3c640362f93a9f0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/RenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1b8c55e9add54a5fac3a8ac21d8179603cb15927404f232df6d680032c4766c2", + "entry_digest": "a47c2aecc5415e209d1e3720b8c5dcaf6791c455392ab433f8ade9e5dc344446", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureBlockPerformanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "80952a163fead38bdc3c122987ec343279450baba2045bafa0dee29c04880f80", + "entry_digest": "d2d47846653eda352f0657b6b77efe4e81399f8dca22ed76eab66820de26f08a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureLiveVoxelTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "301eee13272a74edc54634032d98573c3de42f08ccf201e0896ca8b9b2a81508", + "entry_digest": "26dac0d2c1249e4886f72342f35eb5511f4859400f5c984067e4a1189109db03", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureLiveWorldTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "c9323f4b9e474df331ec909a8ba1090e06cf914270025b1e3bf2e01c8e3b0f83", + "entry_digest": "6eb27aa90a9062780d33fac6711f7ac16a4dbb6ace06a1f6d86bc378a5f4e457", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureSolarPerformanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "3c1ce44b4fc58cfff129459392f6ebb110a2323a96578ef79036b8d4950c3645", + "entry_digest": "46fdaacde44d35048586a3ba1acd65919c8a7a4fb5e72555d3813025fe31b272", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureVolumeStudyRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "2d0c4125cfac669af2c11ddcd8fdd0cf723a2421b69f50d5ed12619a9821a2c9", + "entry_digest": "ba80497b582a3908e9024b78127f6865ee750cbe1ee25561be1614f43173fa57", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureVoxelMeshBuffersTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "a449d8911a0232f7a715f55fcb5ba82cff55c7be66ef02f6dced56bb7437dfc3", + "entry_digest": "885e360f6eaa18e98b43c748e609041f84f03ebcb3a64fa94923b13effaaf8af", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureVoxelSurfaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "aac13532d28070b1e21e403221dcc2f62c42782061ddd9e909cefe86c254d321", + "entry_digest": "d1ec3dde38b4b6aa75ba70301955515676a5d715c4bffcc89bfc06624dde8b1f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureWorldCoarseMeshTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "b902837a81e045b0eec168bedb1ac31a53aec17482717ad74059d38ddb75c647", + "entry_digest": "64109be91cf7d5498bbfb5c01e9656784d1aad6459cc69d482df9b78b6b3a923", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureWorldExplorationRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "041f2376b73e99842c64c067c47616ac9f01012b32d1a00109deb58eb520dfe6", + "entry_digest": "fe16e247d815121af27028365a94c54aec3f0211dc991d06129e70f0239dea41", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureWorldNavigationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f0ce519cf2563b7d14df724921e84090ec746ca4fbc3e907242c467ef95a911f", + "entry_digest": "7ea1cb8275ea18f230130886f854953ff3adaf3dda094a01132083f76c33f4e0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/VoxelRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "4a5ac9a9df5b4185d26a49b5aa5833f0461f9cdde5f0361298300a61d482436f", + "entry_digest": "b36ce9ef6c19677100d1a413fa26ce6741327f0bd425ddb1051656f6e7990ffb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/OBJExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "60732ad89b9f8d2550c20181cfbe94eeaf681c0601ab875fada89a0f77db0e71", + "entry_digest": "faec44c55bb5684ae1264f305072c6d0b02af31e19723249e3b335171e5e5069", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureBinaryCodecTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "70f74e67f0b717f3b95356432f7ff711d4a534e2bd50edeeea97a4d1210aac03", + "entry_digest": "c2b4b21c418ab6ebcd567ef6e7eb9a6325c8cc8d78c7c5856e4f67ffca9c86ce", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureBlockWorldExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "039d7c47a0cbe841055b268fe9289666d71087a1fe3562820239b3638454f936", + "entry_digest": "e44b57919db2694e078de25a2f0c0441dceb248897d095e1201e979404454e8c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureCommandTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "02e10f73e64ac659180fc45f5725b8b1432e81b31dd4765490df53d67cfec586", + "entry_digest": "06201a7a1e9c66820e60093a62d12337396f83d13ce3130636f6fd76e22ac34c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureComplexExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "c4a3434d8a1d19d8895ce9dd72afa8411618784834d745f3c6eb286c81c654b6", + "entry_digest": "e0648397808adfe1708087ca7982d1e46e1276bde43132860f3b0bc90bd7f425", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureCompositionExampleTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ef520f1abb6f4a954d1aafe9b204048c950a188193186b7691cc7f5bcaa51044", + "entry_digest": "ea402f3bd20ed0fbc695eb258ecbac1c82fc14617c09ced252208e45b7d32611", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureCompositionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6e8688d42e9ce3e615266bbb70aa4a711b8ec0be9260d2f97a9a3a64cb2763fa", + "entry_digest": "36805828906c5d3f39c3c719e21cfff1fa0d45c6057dc9bbceefaae7de3a5312", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "a4d8dcff1c2a6152c99c1ed525df5cff9b6b32d6a010f7eca6ea71fe1a47e149", + "entry_digest": "d26f325afaab4a53e5d7756e3cbbac67e68ec10c57da46da92d203af965a1c94", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureGalleryCatalogTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "5e1251834b5ed01919fca0cac7c94e6b6123e977852139e15310d297362ddd0a", + "entry_digest": "651bf5db79ef27172893e498e55f076f41f96e310f2cda6dc01ef7624e7db90b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureInsertionPlanTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "46877cd8e7728cf48edfb215119272203beb8952197665f486b519d813221cd2", + "entry_digest": "30b6c21094328b585abe448848e2b27a54f46ba0b7920b2d094870430b4cff14", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedBundleTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "3bcedcc807cdff72bba12f67d1328ef51c56c808f815b30db2e454ae88d7e981", + "entry_digest": "b608a8af9a7a8673ce114f160955a1ac43b30d9c108427bc8fe093ab99738397", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedCodecTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "708db8b0466433baebdd602b998c1fd92f6bc19e2c01f06ae887bf5499025374", + "entry_digest": "14087dd5c9b94d167d3d7b627cbc91eb5cec0e62236304f9445797d3d0eadb98", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedResolverTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1bf28714d53e7bdd2ac1618523db00ea52c25fb6ebdcbe671f195ed7e66ed8b3", + "entry_digest": "be31783934613156e9ba6f5ffd07d43a4b674e3f5103b22972d474d85ba28579", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedTestProject.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "7c58688450b2a2ec05e8a02760ac3900bda0529afd74801ee4947c83c271dd06", + "entry_digest": "35270a4af37492c0f17970b7e22d60c758369a0afec6e5da4c3bf4804fbba200", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureMathExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f5484b9a660e60b56ee8f5b120a89772d8e0d00a47847282de20c2400903cbff", + "entry_digest": "1f3d00d56343e9032c909098ff307eb2af3b2daefbfb0fa0f2572652d89e2c1f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureModelEditingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "e7b42d35b25e6e300c2902865a5ac14243424b399b32b5f6758cba1cbea73d02", + "entry_digest": "1152d93baba36cc36bf9cf58cea1edb415b68eac388d9045b34779392311ec9b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureSceneInsertionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "8fd2a64110e1b16d3a0d4aa659654a8917d1c2e30d8979fdc6d8e7f4a01d536a", + "entry_digest": "cfbebbcc9c640c3fe802fe7f35c9d83f2fd28f5290ffdcc005c1af03192cc42b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureSolarSystemTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "92196a47f8019ac8b401d26ce870a23625129715ab662255e9f012ddfe01100a", + "entry_digest": "f4750ff963ee8985923b6cbfbcc080cc86c8563f3d212ffa776b69d66a1ecc5e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f2c0ad80603214526f465de7c3b163f61b06a6a9c6ef6cc95ccf389938ef420a", + "entry_digest": "90f35c1f483a6bf2c617076a7357e5423ef44faf8bd00fe7166b3da1e0f1bdb2", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureThreeMDTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "cbbd5b3524e3352d7af5ac9329bea74733625fd6bdf59a94c2f2d50a699fd7db", + "entry_digest": "56ea7a30fbec0e5388795f57f521d6dc488e39b4eab3d743886a7911d7c7d0b9", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureVolumeStudyExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c2c59c4356ed520057f2400140121015b6dc764536047db4a3e48fd7de213b", + "entry_digest": "5e640a40b56fcfc3e636f88b12e747ea717a8721581452f2788d12f65db50df2", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureWorldTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ba5da7db4d78930c8c3de11067c9f3b3f15f579ae8683acf3c400b73e6ae78fc", + "entry_digest": "47ec1e0a3d8cee47068cae4f424d533cedb8d26c830138fe84d7132dfd2b94b3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureCommandToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "db678464dfb484dc5e18c35b3ba87d27e4a416894f7da0328e95f460efdeff7d", + "entry_digest": "70a2958f4e3aea91ca3372d237a29cc73f466ed6f03c809c7f4062643c51c6d7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureInsertToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "7858f7a64fc90e7209239a3a484ccd72e9c37559bc706e7d3c423aeb48cf05e3", + "entry_digest": "7380b1022f8246a0e0a5cdaa542e1009619081783feeb7c6160b02c0df63bd62", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureLinkedInputTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "7f12f1bda9a5cef9400e254f6cb83c42e8c33de082ad9ef9e3e4dbd895bc6e78", + "entry_digest": "b07535e693f420d76018263ad8264478d9433f433f36ec00c73832e9fd14f097", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureMathExampleExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "62eb5b7b9297c274e6d8cb34f26b13a35a06efea25c713bf9e7b35b889fc99af", + "entry_digest": "44e9cef15854aedfb6451c5fefdc876b7ecfb39993297cafd835a4fbb361d345", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculpturePortableToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "93fe986fecb606b1efc64ccdfc1e5c6a6c9c42805cd8c85a3b81656265e6b37f", + "entry_digest": "9038516bee6cc12abf8effccaab28b84b1be76cb7d62d606796cc0bea7a96466", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureReferenceModelToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f9f9d80ed84ac2593de24f81d757d6520c06a805e0c8e59c82ef2629fa02b424", + "entry_digest": "dfbe8fe8b77a41a921880178e874657bbca35a5ae953fb251c18dc50a2fe32ac", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureVolumeStudyTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "8a8396041daabd97bdd52c695b165d3bd365106b79d891f90982440f302c466b", + "entry_digest": "e912b7d78aaee2840f25472293b007f6c207e1c7c06d3ee6e8cf2237d5a69c30", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureVolumeStudyWorldExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "421c70bb22e030ba15953f1f0c43a7511c80b8e35db9dab1e2c8d891881454a8", + "entry_digest": "937f9e8403bcf017ca424ac3848e39d61231e74cd3273ca33c1a07590b12dd7a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureWorldToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "833b235acca092fd2dca1f7bb5ed4f0493cb8cb53120fe59d97fe441520eabda", + "entry_digest": "e6af00f53db1883e3972a2cbbb81a807c583e169dd985c91ec792bf0dd8495db", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolingTests/NativeToolsTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "9058e47f3ed1b6bd6742067d0418aead0d180b10ce2acaef5d76d76a1de7f617", + "entry_digest": "9ab8dc927319357c20902e50fe1faa16fa6c0d74486069e6b7deef7a72a8e906", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookVerificationTests/RunnerTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "a13fa9e4c75fbb6024eb8a962248b05602d752c44e52eb38f6a3085e9a8a1d34", + "entry_digest": "0bf2794629b02e647ce705a09a0752b877d6c8ec18c27e899c1c5c1c2c58a500", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookVerificationTests/SwiftTestLogTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d81d429bb0f794b33c8858dcc47c8735d452cff72281b1a04bd55c974f5ad904", + "entry_digest": "dc62c3d4c6032f34439560e68ce01085f2e198319832859089b2f2b55999f8dd", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "5b1180aa1683357d4fbdc6f70c7a6f099ba574be8eeacb6122c34f3fbd6e5a3d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a7c2b4f3e362bf812e2d342e821615c65cf67ba782d03a07a6627bc04b5c9252", + "entry_digest": "1722750a8a857e473be446b70ff76dac1d842fdf4ff493b14d06a4a22a9bb40a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/CLAUDE.md", + "kind": "symlink", + "mode": 40960, + "payload_digest": "a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9", + "entry_digest": "2e936d4157c977b650afd28e14fc3706e93690ec69f2a1cd258a8a0033db5ac0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/composition.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4192061cfc0862a5287229adac316bdfdca78c326a1ecc0a9884843e683afd43", + "entry_digest": "ccce7bef24717df3e210139e37c06279fa50bdf023409d9f696be23f60c03d0b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/cubes.md", + "kind": "file", + "mode": 33188, + "payload_digest": "87717022e44982d6ca2c7b737c614a5e836a63f87fda234949e6b2ff21849e0c", + "entry_digest": "923d5bb8afcf10e3fed111038afa5196f69068226804bf328152429336aa17b8", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/export.md", + "kind": "file", + "mode": 33188, + "payload_digest": "88a062b3c77f0612fd9a8b4c531b31d7df0fa3023aa9eb78739668bf0fc9a63d", + "entry_digest": "fafdb5908519d66ff163f83e8e83ba4e53ee12c2a44219ab2a0ad96222a2168a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/gallery.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3091b9b84faf7b8d76e0c98ab633d043d2614dce43b02bacfc47a2d87ee7d3a3", + "entry_digest": "dcc0b0a9ca005f63b81ada36d8a594c9b6baffde5ed4ec08fc083de3abe50e58", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/local.md", + "kind": "file", + "mode": 33188, + "payload_digest": "5289ba2802b24f18a6afe990ddb4276faf2297c6cae75a964c9905c189f99033", + "entry_digest": "36bf50f6d883038c37dbec78d697784287e22046eff83e585ba5dc6c5b5f816c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/render.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b0923791421fc00c64725b77e0dce6dd223cf950e1fe40bbab7fe71160b63338", + "entry_digest": "9a3d081a42bc70cd32d2ad397e38bc6e4bd350df2b3124d076eb36228294e7d0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/sculpture.md", + "kind": "file", + "mode": 33188, + "payload_digest": "7116a830b65f7af632d2b2d2aa77e567631c2a33a7fcb5d3b9cd3a3d57082271", + "entry_digest": "caea0e7869eae9c61e45f6cdca43df6afbc1b81cc333ca602744fc342db91f2d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/shell.md", + "kind": "file", + "mode": 33188, + "payload_digest": "d8fb4017d5a6dad0adc64617d8d7289001dc0cdac3e33e1ceb9f1f644fda49f5", + "entry_digest": "fbbea37430b6614be789611f97c9f2e5337cdc8df825e4945cd078e988359987", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/slice.md", + "kind": "file", + "mode": 33188, + "payload_digest": "295ed1d6feff3b478fb6a7f751feb35cee475ab60d94e214bc04d3f639c2e546", + "entry_digest": "357fdb9cb2e2b1e44d3cd2372ba1cad4cc6b1ede97d0003be1221473c5e98bfb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/world.md", + "kind": "file", + "mode": 33188, + "payload_digest": "663559da5bb02db3413f545de91e81ffd7ab5c3890158aeaec964d819c1ded5a", + "entry_digest": "6b2354660f0978b98ab1c58356d2fc585763ac09e078b5f988e14f6493255e74", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "f4fb94115c0cd72e416a30a3a454bbbda63ac0989744dd1fa148551cef9875ef", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookApp/RookApp.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "328f0e0ec49767f115960ba7a09b1395626ef6dd78cdb76f79ffc61d3b381859", + "entry_digest": "9b423979478d8e5435ad55cefb13fd9f1cb745b718a28367a176d282ab385f26", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookApp/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a998087ec9c46dec9d5e3f6e3f4c2680966f67d766be19fe3a7a1c9ae9fec9d3", + "entry_digest": "29b6f5ed8b2d484afc100b05e971236b61d7e4ee48637788c1799a205da5236e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookCore/RookCore.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "edd8f788a56817afc8eb2d477a0a75f3bc37135d205b1f6e9665d03ff0b74344", + "entry_digest": "729f1a3b27ad303e7b38f7aa49372a4ef57113a9014060cbff46c2cc2fd6a810", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookCore/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "80305947b009aeab89c4fae62bc8ef48cb0c6c95cfbd351cea9e2fc0f47a0b21", + "entry_digest": "c5d7038b613041d8fabe4e2dc47fc2fc08efe5774e9551e50648763eca8d2cf8", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookDevelopment/RookDevelopment.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b2c021c8fa8d74dc2197bd5ef8754e4f3eadb091c743831ad643b7867588c9d0", + "entry_digest": "319c60159eecb9efbd78bb2a137c83b5e0d6357cdb6e72aa96ff86e80a7d3adb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookDevelopment/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "0efd07ebb2fa2d12769429f782dd1d2d70362adbeca2a82234251c6aa55abe90", + "entry_digest": "a11e80095e0bb66c0baba88236129a1ebef28c54ea2f454e2362c70467a6f960", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookRendering/RookRendering.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3eaeae84bde150f19ca189a04310b28dda74cfb90d55430c8835f07b1ee1008d", + "entry_digest": "65bb892edfa4ca765ffc6556cc977b0af8cd62ccfed702f5c71266ac30debb37", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookRendering/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "9360c435f8fb30b54a7fa3e411a6d8f5347e089ea9038a80734fc821b49dcdcf", + "entry_digest": "17c88752e827fc1622f4a732707fcb86865a43baf1ef6630541f2b0c584f6521", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookSculpture/RookSculpture.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a89be62701494e3b6c7ffbde27888091fe3c0d7d81fb91813fe697686d0381ae", + "entry_digest": "33ea611aec1446b7377f396832436a2f23db9075d8466462a978d6b04554d412", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookSculpture/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "fddb51105fb11306fc54c53f1c74771fde301812c8a3da5a253108ec89b5000d", + "entry_digest": "3d9dd7140bc5cfe762961be8d7cd0c7fa5369d44dd46ea208384221979a0fa5f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "hi/tools.md", + "kind": "file", + "mode": 33188, + "payload_digest": "cd530f076ed449b2dcd994f9178fcb104f4460e44a12042200b42bf6ca6d6306", + "entry_digest": "a13f216eb32a3671d7563024082ab76eb471bdd7a2ddb3c3398b672b05354a70", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/ThreeMDViewer", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "b53a01354acef7fb830687d9789c70f85c60f43e94da4a2dd0816c771a3bf773", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/ThreeMDViewer.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3b3b09952c692c501a98d6520fb8a82f5126ab9b05d64f6634b50cbae3620ae6", + "entry_digest": "64224b139df2b01fdd0db61c4817d9a836030dbf2667bda60529f6a61be627b4", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a0011f2d32b7dce6370e015fefcf09acbcf52578e82a97e56def17e0e0fbed52", + "entry_digest": "e020a4426da69e6b24dd3025c95afd9a88cf073bca235f86ad9104e1de81c7f7", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96612855952a65a5e6b623e2b5d21e9dd8f4ea88c92c0e8ef392e3b826b81f94", + "entry_digest": "5caf30173677b31dcf1119406f03f7dd5a1721487ef58ceacb8d22ed07244d4d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4b0a856509eb4b4c0c875e4b74844c45ce162acf255ce69bf88f86d82feae603", + "entry_digest": "3767a753d3d8c88a88e61820f68b82317f5cd533b57cec5ddc798c7d33ef2656", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e224b1bc77ea1679aa4cbd34f182846717be905bec43bff555d19f0ba5f75b15", + "entry_digest": "fee23d7cfc7097bb6cda3f52a2a0efd8ae2030ec4c32059529bccb53252bc7e1", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "uitests/viewer.spec.mjs", + "kind": "file", + "mode": 33188, + "payload_digest": "52dd2553472620fd956815792cb22c70980c8d70ea4563eac487ec5eb4f28093", + "entry_digest": "05c24eeea687cd37e72eaa5382b93877334fb1cb53ab1b80babe625a09d0393b", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "web/viewer.html", + "kind": "file", + "mode": 33188, + "payload_digest": "457af08a02075688bdec1285f820bd6e6ff48e54c392a6239d3a0519a21197b2", + "entry_digest": "91188b507e047ae68fe1e96a1980f5b33206532a2cabafec98e7d7883e0b70e4", + "owners": [ + "ThreeMDViewer" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] + } + ] +} diff --git a/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json new file mode 100644 index 0000000..8456a07 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json @@ -0,0 +1,1214 @@ +{ + "timestamp": 1791655884, + "commit": "60055f7806a4d46964b766672784be45713e3c3a", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", + "acceptance_input_digest": "75c60a31bc1b305db3d7f15f76d65654d7a80eea3669ed8ed768701654a163a0", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": "apps/sculpt/Sources/RookApp/SculptureViewport.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "8d5ab6c914e03d60dadc58a3e8b6d4f595a261b1e032c46cc0cdbd0597757e45", + "entry_digest": "24442eef4a7215ed811720b44e4f3014ac30df390846447f342ebe7b9d94ff1d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Sources/RookRendering/SculptureLiveVoxelView.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "610272100afb40b290302e64c8cf72544b67f3c2cee3543b292f796531c9750e", + "entry_digest": "210439bcd02c86c1940dbec87538b50db5a465257538913389cb8d82d767fe6c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Sources/RookRendering/SculptureVoxelGeometry.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "24c096ecd359193366e02097643561e28fb3ff422e1fafda1661dbf0f706eb86", + "entry_digest": "b2ff90dc0d60eeb4fdc2983e7c2a13382859ab24164d5d355787aaf98bbe6807", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Sources/RookSculpture/SculptureProjection.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d98745e56609642d7c65369aa67f251d82c3c6089199cd6a2bcc9b1fc928c8d4", + "entry_digest": "22f5d1bb30035cd28eea2c7ed2df463a4ecd679601edeacc7f3e591b9485e267", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "094f12e742e15c4721c78566d011dd8f2dacfdf163828f9b9e12e6dbbfab2764", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/AppearanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "bb460ca170501c02f7e413b1c85c41f0decef55aba4ea735f32c226c36e894e5", + "entry_digest": "ff7f1cf01c86f9e9c1964067854027d5bd8ef674a0894206b189c97a0520df23", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/LayerGridGeometryTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6645f57ab9861bcab490fd53808b6a178c57ae6833e51f4575c31c95f641ef46", + "entry_digest": "abc7fbc1e12be39495e89853bcdaab5cec35152d1d0e48d8c1828c3755e6ded1", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/LayerGridScrollPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1533740a7d0e2347a50bc5ac3ac8ba08037dbc8ac7e3b3c50c022b53f49a765c", + "entry_digest": "a5134e75f1746ab129d9f84012691cc39727df27949a5bce4c6e65ba6d75fa16", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureCanvasPointerTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "2eeb532f40db634a0674a94857aed000224be0526de24fc72a000a2570991883", + "entry_digest": "7e2b1210b7a3eb39e7ebcd1a03d4307a65b2fff0f6181e1ba4be83eb0bc2d5cb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureCommandFocusTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "25fb256f29a8991b87e65f09b8caad37711390bf5c7f31da242bbffc13001576", + "entry_digest": "29bbd13e54d55add0704a17c81ad8da3609d7edac595fd6d499105e2e038d9ed", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureCompositionEditorTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "19bb8062f643d384cdee5e768ed856c9d6b7331980d5987164adbb2973027e3f", + "entry_digest": "d733318c97c4ee44e5ae4376cecff5a69567703d854230b84167bbad055aaad2", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureEditorPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ded50853676c0ad3bd625c55d4aaca9769c8e803a04f38ada6c59ae2f49fb095", + "entry_digest": "c75be12388c9fd7c9406e1c524e6d6a339092527fd75575a70927918d22f385d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureExportJobTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "0101679374acf6525820313028313573b49605c068286d1923b7c3d6986ed675", + "entry_digest": "54c858f1e9b793276d3fa7f1b6f2d4249830ab1229f46f3fed4f48e406706616", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureGalleryBrowserTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "59dcb942153a452120eeabe743a971fa707032ed422b24db19876238f3747b6b", + "entry_digest": "2280e89bb09b6dc17012fea72e1a3bda59c7e1d0504039430317ece2ee21a115", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureGraphSaveJobTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "b3c9b2b8bbf482a27161aef9d1ad0bd161353678319ecfc7e833655b6673276c", + "entry_digest": "62c72b46d143f2d230e7e291b4c5c4f5517666e1459fe3181f507c65624db824", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureInsertionDiscoveryTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "18c78362b45c16063ca9cf888e6376ec1bc56872a2e95261257f7fbe7b363f9b", + "entry_digest": "9057cc0eecaffe749a2c592b04ee299624a3a791c8f6e89e9952ca49b3a5187f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureInsertionDraftTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "5efc2d96cdbd08514532647eaa7ca762152f211e99665955f0d081f1478a0d72", + "entry_digest": "c93a1807c59024d7836c48968f603168ae5abf5c18754ce75638beb38999d446", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureInsertionRepairTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6b0fa86e435c43766b7ede2207afc87f460236138c8deaf5b267ac016214a2b1", + "entry_digest": "854eb3a494a8844e8db408b7ea4f42304e8863fea8122776957f6d90da0585c4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedConfinementTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "5b1ec9e5b39bdd52833a9003a62cf63f5c1e88896fce4962120345af7f868849", + "entry_digest": "26d045fd6441c6c932b8497303ba52a107129baedddf46c32d26db5eb2cc8800", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedInsertionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "e8947fbf69251f81c231f8c2936cfdf8558d8240399ab16369c7bee07b78b2de", + "entry_digest": "80649740dee2b7daf7858ad82f009827d83084e20672f2e08768b08df523e563", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d703a36c7eaac77ef95251a924e5f2275a9d1fc2874d053816590d700bb79bb4", + "entry_digest": "bc53d1a4d3030610a40da15cef40c1e4fb4ec8492dc278ac44c285e940ef9797", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedSessionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "afb46a2e240b948ea168b80d3b918090908db29b0e42d14fa17e689862dfb9b0", + "entry_digest": "9de38710e6bcac83215b68343eaa1fdec0e42ca5310fd9899ce9d3edee188e16", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureLinkedTestProject.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "c8e07629a75cb25558958ac0ab6de0a383f3962f4f9ef9d53623de8a790251c5", + "entry_digest": "39ca31385c1dc4f6ce086f4edefa4a2fdaf229d7212db2819ec4c0dd886a5db5", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureMeshRevisionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "49950faf4516bdbb9f46d1d6382b12e50f2e1e50cb19b24786b9f24b17ef237d", + "entry_digest": "7ba09620fe295e049072120b8295ff92f7b1637701d435a4a3318a8a9ee6aaee", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculpturePortableInterchangeTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "e33d0ecc55db21dea1e7a22c4c53d08d964bf65cfac4482113228328ba5202e2", + "entry_digest": "bfb5e8f52204376972583ec77fed86a25f79cc65a3d865b68c372b8c6036463c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureReferenceEditorPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6f8f32bafce36b5b50625c5959a3f52b64b1ff87d10200423e4a813e3c15facf", + "entry_digest": "c63963edb0b237f7d076eb1da498122467f07c129f8a294dbb953cec825681d1", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureReferenceSaveSessionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "4f19a8645355e5537b3de91c5d7ce9334cdc20da7cbc334da464b69098c492e5", + "entry_digest": "5fc3bec2792e589ede91c109f0c279256616ca736c99afdcd3d333d20fd53bf7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureSaveJobTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "49808899eefe4ed5e8e0a1ce701749f6d4ef82ff540bff5473c1b5dd634a37c7", + "entry_digest": "3f5101a4313935905c0ce901ce18506f3ebadfa5412b4c770a7c2207dc68c4ab", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureSharedModelDraftTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "03fc1f9626cd365c84421b581d27b42f842908a09d4cc014939f5dda34cc352f", + "entry_digest": "c4a4e09309acd95d18e227ae25e495f2e44c4ed5f40801e34b347d893297be3f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureSharedModelPresentationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "0e4a7bc7a44619ecd9a001c21e2a29adfdf3b9da9d5a1bfdc7ac0c06a889f336", + "entry_digest": "9b37c492d9734c1aecfde57c7f41568d518020cad3e65e42d3e7d2aa6c9266aa", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureVoxelWorkspaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "085c78d6a0f10a7a63859feb3783dea5a21ff651bd8641618f29bdd0c9c020ab", + "entry_digest": "cb4638941514ef448fce96171889541f28e5cb2fb1d455b0ea8e8b22ac633a30", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureWorkspaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f420db050af7dea627b63e3b33e113377e3919b69d24b7d4e5a97a6bcd06c681", + "entry_digest": "997ec23ca0eacd6cd532071f3da63de1da66eb5a0f11ba6902520e84b68c637b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SculptureWorldEditorTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "51707a0e3b30bdb26826e1f0119b1725d39d735df5e7a3de255fe56e294b7922", + "entry_digest": "5b5b3030f6d5fd568e07c8153d7c155e2ec1a224a582b35f54013f6f567f64e4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookAppTests/SliceGridRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f0d9c2da996754a881e260ac2a7b5b5b81406f5cf97ec857bf92e62edaea9cf0", + "entry_digest": "82df33fc6af7c834ad6b35e2edd38724ca63c5201ee0bc7200ddec753e63757c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookCoreTests/AppAppearanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "96b116fa629f3753d8b42934a811c1428f31636e2856db12bd9f583a9126c368", + "entry_digest": "556583436e1058dc662eef44661aae7333461f13160a1f06a9e1ca9f5fbc006e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/AnimationExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "703d05088f785075738fd195c924270259f2a471566e1b5872881117239fc942", + "entry_digest": "29b0fb1b5fc6a8d6e710a872bf02d19848f68b1d0fdca7a7e06a4e4f2f5042d8", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/CameraParityTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "97c1b35abd129f1f8fc3a2e3fec0ede9b4416b5a0bdd0c53eb55877dca353c6d", + "entry_digest": "7d2c516df02831b4c7701e5d5d3fd31791d99cb6d7b456bd177db175f8fd9c2b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/CubeExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6bff8220f252746e5591956209d228de11b97b8b46e98d0ea09ae13f93c3e324", + "entry_digest": "d76039bb23eb138a74b6e89671c99768c725e12b1760b8582aa64942ddb9665a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/ExampleArtifactTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "affec5f8e6b1f6cb461373dc77d8b1029cafecf2afdb13c1936f15744d055e4b", + "entry_digest": "800fb1804c6303bef36f066056b3cff1fc272c25d83cd619dd9319e463a0b683", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/PreparedVoxelProjectionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "0e828abc9fdfd275524439149a7767457afec885207c9483d64e876e9a4feaf8", + "entry_digest": "af9ffdfd90d0fdaaa3393c432448e3f955318e2754321f66e3c640362f93a9f0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/RenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1b8c55e9add54a5fac3a8ac21d8179603cb15927404f232df6d680032c4766c2", + "entry_digest": "a47c2aecc5415e209d1e3720b8c5dcaf6791c455392ab433f8ade9e5dc344446", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureBlockPerformanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "80952a163fead38bdc3c122987ec343279450baba2045bafa0dee29c04880f80", + "entry_digest": "d2d47846653eda352f0657b6b77efe4e81399f8dca22ed76eab66820de26f08a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureLiveVoxelTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "301eee13272a74edc54634032d98573c3de42f08ccf201e0896ca8b9b2a81508", + "entry_digest": "26dac0d2c1249e4886f72342f35eb5511f4859400f5c984067e4a1189109db03", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureLiveWorldTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "c9323f4b9e474df331ec909a8ba1090e06cf914270025b1e3bf2e01c8e3b0f83", + "entry_digest": "6eb27aa90a9062780d33fac6711f7ac16a4dbb6ace06a1f6d86bc378a5f4e457", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureSolarPerformanceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "3c1ce44b4fc58cfff129459392f6ebb110a2323a96578ef79036b8d4950c3645", + "entry_digest": "46fdaacde44d35048586a3ba1acd65919c8a7a4fb5e72555d3813025fe31b272", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureVolumeStudyRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "2d0c4125cfac669af2c11ddcd8fdd0cf723a2421b69f50d5ed12619a9821a2c9", + "entry_digest": "ba80497b582a3908e9024b78127f6865ee750cbe1ee25561be1614f43173fa57", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureVoxelMeshBuffersTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "a449d8911a0232f7a715f55fcb5ba82cff55c7be66ef02f6dced56bb7437dfc3", + "entry_digest": "885e360f6eaa18e98b43c748e609041f84f03ebcb3a64fa94923b13effaaf8af", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureVoxelSurfaceTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "aac13532d28070b1e21e403221dcc2f62c42782061ddd9e909cefe86c254d321", + "entry_digest": "d1ec3dde38b4b6aa75ba70301955515676a5d715c4bffcc89bfc06624dde8b1f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureWorldCoarseMeshTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "b902837a81e045b0eec168bedb1ac31a53aec17482717ad74059d38ddb75c647", + "entry_digest": "64109be91cf7d5498bbfb5c01e9656784d1aad6459cc69d482df9b78b6b3a923", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureWorldExplorationRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "041f2376b73e99842c64c067c47616ac9f01012b32d1a00109deb58eb520dfe6", + "entry_digest": "fe16e247d815121af27028365a94c54aec3f0211dc991d06129e70f0239dea41", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/SculptureWorldNavigationTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f0ce519cf2563b7d14df724921e84090ec746ca4fbc3e907242c467ef95a911f", + "entry_digest": "7ea1cb8275ea18f230130886f854953ff3adaf3dda094a01132083f76c33f4e0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookRenderingTests/VoxelRenderingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "4a5ac9a9df5b4185d26a49b5aa5833f0461f9cdde5f0361298300a61d482436f", + "entry_digest": "b36ce9ef6c19677100d1a413fa26ce6741327f0bd425ddb1051656f6e7990ffb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/OBJExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "60732ad89b9f8d2550c20181cfbe94eeaf681c0601ab875fada89a0f77db0e71", + "entry_digest": "faec44c55bb5684ae1264f305072c6d0b02af31e19723249e3b335171e5e5069", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureBinaryCodecTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "70f74e67f0b717f3b95356432f7ff711d4a534e2bd50edeeea97a4d1210aac03", + "entry_digest": "c2b4b21c418ab6ebcd567ef6e7eb9a6325c8cc8d78c7c5856e4f67ffca9c86ce", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureBlockWorldExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "039d7c47a0cbe841055b268fe9289666d71087a1fe3562820239b3638454f936", + "entry_digest": "e44b57919db2694e078de25a2f0c0441dceb248897d095e1201e979404454e8c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureCommandTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "02e10f73e64ac659180fc45f5725b8b1432e81b31dd4765490df53d67cfec586", + "entry_digest": "06201a7a1e9c66820e60093a62d12337396f83d13ce3130636f6fd76e22ac34c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureComplexExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "c4a3434d8a1d19d8895ce9dd72afa8411618784834d745f3c6eb286c81c654b6", + "entry_digest": "e0648397808adfe1708087ca7982d1e46e1276bde43132860f3b0bc90bd7f425", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureCompositionExampleTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ef520f1abb6f4a954d1aafe9b204048c950a188193186b7691cc7f5bcaa51044", + "entry_digest": "ea402f3bd20ed0fbc695eb258ecbac1c82fc14617c09ced252208e45b7d32611", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureCompositionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "6e8688d42e9ce3e615266bbb70aa4a711b8ec0be9260d2f97a9a3a64cb2763fa", + "entry_digest": "36805828906c5d3f39c3c719e21cfff1fa0d45c6057dc9bbceefaae7de3a5312", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "a4d8dcff1c2a6152c99c1ed525df5cff9b6b32d6a010f7eca6ea71fe1a47e149", + "entry_digest": "d26f325afaab4a53e5d7756e3cbbac67e68ec10c57da46da92d203af965a1c94", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureGalleryCatalogTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "5e1251834b5ed01919fca0cac7c94e6b6123e977852139e15310d297362ddd0a", + "entry_digest": "651bf5db79ef27172893e498e55f076f41f96e310f2cda6dc01ef7624e7db90b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureInsertionPlanTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "46877cd8e7728cf48edfb215119272203beb8952197665f486b519d813221cd2", + "entry_digest": "30b6c21094328b585abe448848e2b27a54f46ba0b7920b2d094870430b4cff14", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedBundleTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "3bcedcc807cdff72bba12f67d1328ef51c56c808f815b30db2e454ae88d7e981", + "entry_digest": "b608a8af9a7a8673ce114f160955a1ac43b30d9c108427bc8fe093ab99738397", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedCodecTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "708db8b0466433baebdd602b998c1fd92f6bc19e2c01f06ae887bf5499025374", + "entry_digest": "14087dd5c9b94d167d3d7b627cbc91eb5cec0e62236304f9445797d3d0eadb98", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedResolverTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "1bf28714d53e7bdd2ac1618523db00ea52c25fb6ebdcbe671f195ed7e66ed8b3", + "entry_digest": "be31783934613156e9ba6f5ffd07d43a4b674e3f5103b22972d474d85ba28579", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureLinkedTestProject.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "7c58688450b2a2ec05e8a02760ac3900bda0529afd74801ee4947c83c271dd06", + "entry_digest": "35270a4af37492c0f17970b7e22d60c758369a0afec6e5da4c3bf4804fbba200", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureMathExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f5484b9a660e60b56ee8f5b120a89772d8e0d00a47847282de20c2400903cbff", + "entry_digest": "1f3d00d56343e9032c909098ff307eb2af3b2daefbfb0fa0f2572652d89e2c1f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureModelEditingTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "e7b42d35b25e6e300c2902865a5ac14243424b399b32b5f6758cba1cbea73d02", + "entry_digest": "1152d93baba36cc36bf9cf58cea1edb415b68eac388d9045b34779392311ec9b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureSceneInsertionTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "8fd2a64110e1b16d3a0d4aa659654a8917d1c2e30d8979fdc6d8e7f4a01d536a", + "entry_digest": "cfbebbcc9c640c3fe802fe7f35c9d83f2fd28f5290ffdcc005c1af03192cc42b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureSolarSystemTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "92196a47f8019ac8b401d26ce870a23625129715ab662255e9f012ddfe01100a", + "entry_digest": "f4750ff963ee8985923b6cbfbcc080cc86c8563f3d212ffa776b69d66a1ecc5e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f2c0ad80603214526f465de7c3b163f61b06a6a9c6ef6cc95ccf389938ef420a", + "entry_digest": "90f35c1f483a6bf2c617076a7357e5423ef44faf8bd00fe7166b3da1e0f1bdb2", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureThreeMDTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "cbbd5b3524e3352d7af5ac9329bea74733625fd6bdf59a94c2f2d50a699fd7db", + "entry_digest": "56ea7a30fbec0e5388795f57f521d6dc488e39b4eab3d743886a7911d7c7d0b9", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureVolumeStudyExamplesTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "26c2c59c4356ed520057f2400140121015b6dc764536047db4a3e48fd7de213b", + "entry_digest": "5e640a40b56fcfc3e636f88b12e747ea717a8721581452f2788d12f65db50df2", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookSculptureTests/SculptureWorldTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "ba5da7db4d78930c8c3de11067c9f3b3f15f579ae8683acf3c400b73e6ae78fc", + "entry_digest": "47ec1e0a3d8cee47068cae4f424d533cedb8d26c830138fe84d7132dfd2b94b3", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureCommandToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "db678464dfb484dc5e18c35b3ba87d27e4a416894f7da0328e95f460efdeff7d", + "entry_digest": "70a2958f4e3aea91ca3372d237a29cc73f466ed6f03c809c7f4062643c51c6d7", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureInsertToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "7858f7a64fc90e7209239a3a484ccd72e9c37559bc706e7d3c423aeb48cf05e3", + "entry_digest": "7380b1022f8246a0e0a5cdaa542e1009619081783feeb7c6160b02c0df63bd62", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureLinkedInputTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "7f12f1bda9a5cef9400e254f6cb83c42e8c33de082ad9ef9e3e4dbd895bc6e78", + "entry_digest": "b07535e693f420d76018263ad8264478d9433f433f36ec00c73832e9fd14f097", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureMathExampleExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "62eb5b7b9297c274e6d8cb34f26b13a35a06efea25c713bf9e7b35b889fc99af", + "entry_digest": "44e9cef15854aedfb6451c5fefdc876b7ecfb39993297cafd835a4fbb361d345", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculpturePortableToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "93fe986fecb606b1efc64ccdfc1e5c6a6c9c42805cd8c85a3b81656265e6b37f", + "entry_digest": "9038516bee6cc12abf8effccaab28b84b1be76cb7d62d606796cc0bea7a96466", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureReferenceModelToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "f9f9d80ed84ac2593de24f81d757d6520c06a805e0c8e59c82ef2629fa02b424", + "entry_digest": "dfbe8fe8b77a41a921880178e874657bbca35a5ae953fb251c18dc50a2fe32ac", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureVolumeStudyTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "8a8396041daabd97bdd52c695b165d3bd365106b79d891f90982440f302c466b", + "entry_digest": "e912b7d78aaee2840f25472293b007f6c207e1c7c06d3ee6e8cf2237d5a69c30", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureVolumeStudyWorldExportTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "421c70bb22e030ba15953f1f0c43a7511c80b8e35db9dab1e2c8d891881454a8", + "entry_digest": "937f9e8403bcf017ca424ac3848e39d61231e74cd3273ca33c1a07590b12dd7a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolTests/SculptureWorldToolTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "833b235acca092fd2dca1f7bb5ed4f0493cb8cb53120fe59d97fe441520eabda", + "entry_digest": "e6af00f53db1883e3972a2cbbb81a807c583e169dd985c91ec792bf0dd8495db", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookToolingTests/NativeToolsTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "9058e47f3ed1b6bd6742067d0418aead0d180b10ce2acaef5d76d76a1de7f617", + "entry_digest": "9ab8dc927319357c20902e50fe1faa16fa6c0d74486069e6b7deef7a72a8e906", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookVerificationTests/RunnerTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "a13fa9e4c75fbb6024eb8a962248b05602d752c44e52eb38f6a3085e9a8a1d34", + "entry_digest": "0bf2794629b02e647ce705a09a0752b877d6c8ec18c27e899c1c5c1c2c58a500", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/Tests/RookVerificationTests/SwiftTestLogTests.swift", + "kind": "file", + "mode": 33188, + "payload_digest": "d81d429bb0f794b33c8858dcc47c8735d452cff72281b1a04bd55c974f5ad904", + "entry_digest": "dc62c3d4c6032f34439560e68ce01085f2e198319832859089b2f2b55999f8dd", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "5b1180aa1683357d4fbdc6f70c7a6f099ba574be8eeacb6122c34f3fbd6e5a3d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/AGENTS.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a7c2b4f3e362bf812e2d342e821615c65cf67ba782d03a07a6627bc04b5c9252", + "entry_digest": "1722750a8a857e473be446b70ff76dac1d842fdf4ff493b14d06a4a22a9bb40a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/CLAUDE.md", + "kind": "symlink", + "mode": 40960, + "payload_digest": "a54ff182c7e8acf56acfd6e4b9c3ff41e2c41a31c9b211b2deb9df75d9a478f9", + "entry_digest": "2e936d4157c977b650afd28e14fc3706e93690ec69f2a1cd258a8a0033db5ac0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/composition.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4192061cfc0862a5287229adac316bdfdca78c326a1ecc0a9884843e683afd43", + "entry_digest": "ccce7bef24717df3e210139e37c06279fa50bdf023409d9f696be23f60c03d0b", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/cubes.md", + "kind": "file", + "mode": 33188, + "payload_digest": "87717022e44982d6ca2c7b737c614a5e836a63f87fda234949e6b2ff21849e0c", + "entry_digest": "923d5bb8afcf10e3fed111038afa5196f69068226804bf328152429336aa17b8", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/export.md", + "kind": "file", + "mode": 33188, + "payload_digest": "88a062b3c77f0612fd9a8b4c531b31d7df0fa3023aa9eb78739668bf0fc9a63d", + "entry_digest": "fafdb5908519d66ff163f83e8e83ba4e53ee12c2a44219ab2a0ad96222a2168a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/gallery.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3091b9b84faf7b8d76e0c98ab633d043d2614dce43b02bacfc47a2d87ee7d3a3", + "entry_digest": "dcc0b0a9ca005f63b81ada36d8a594c9b6baffde5ed4ec08fc083de3abe50e58", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/local.md", + "kind": "file", + "mode": 33188, + "payload_digest": "5289ba2802b24f18a6afe990ddb4276faf2297c6cae75a964c9905c189f99033", + "entry_digest": "36bf50f6d883038c37dbec78d697784287e22046eff83e585ba5dc6c5b5f816c", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/render.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b0923791421fc00c64725b77e0dce6dd223cf950e1fe40bbab7fe71160b63338", + "entry_digest": "9a3d081a42bc70cd32d2ad397e38bc6e4bd350df2b3124d076eb36228294e7d0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/sculpture.md", + "kind": "file", + "mode": 33188, + "payload_digest": "7116a830b65f7af632d2b2d2aa77e567631c2a33a7fcb5d3b9cd3a3d57082271", + "entry_digest": "caea0e7869eae9c61e45f6cdca43df6afbc1b81cc333ca602744fc342db91f2d", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/shell.md", + "kind": "file", + "mode": 33188, + "payload_digest": "d8fb4017d5a6dad0adc64617d8d7289001dc0cdac3e33e1ceb9f1f644fda49f5", + "entry_digest": "fbbea37430b6614be789611f97c9f2e5337cdc8df825e4945cd078e988359987", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/slice.md", + "kind": "file", + "mode": 33188, + "payload_digest": "295ed1d6feff3b478fb6a7f751feb35cee475ab60d94e214bc04d3f639c2e546", + "entry_digest": "357fdb9cb2e2b1e44d3cd2372ba1cad4cc6b1ede97d0003be1221473c5e98bfb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/hi/world.md", + "kind": "file", + "mode": 33188, + "payload_digest": "663559da5bb02db3413f545de91e81ffd7ab5c3890158aeaec964d819c1ded5a", + "entry_digest": "6b2354660f0978b98ab1c58356d2fc585763ac09e078b5f988e14f6493255e74", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "f4fb94115c0cd72e416a30a3a454bbbda63ac0989744dd1fa148551cef9875ef", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookApp/RookApp.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "328f0e0ec49767f115960ba7a09b1395626ef6dd78cdb76f79ffc61d3b381859", + "entry_digest": "9b423979478d8e5435ad55cefb13fd9f1cb745b718a28367a176d282ab385f26", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookApp/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a998087ec9c46dec9d5e3f6e3f4c2680966f67d766be19fe3a7a1c9ae9fec9d3", + "entry_digest": "29b6f5ed8b2d484afc100b05e971236b61d7e4ee48637788c1799a205da5236e", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookCore/RookCore.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "edd8f788a56817afc8eb2d477a0a75f3bc37135d205b1f6e9665d03ff0b74344", + "entry_digest": "729f1a3b27ad303e7b38f7aa49372a4ef57113a9014060cbff46c2cc2fd6a810", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookCore/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "80305947b009aeab89c4fae62bc8ef48cb0c6c95cfbd351cea9e2fc0f47a0b21", + "entry_digest": "c5d7038b613041d8fabe4e2dc47fc2fc08efe5774e9551e50648763eca8d2cf8", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookDevelopment/RookDevelopment.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "b2c021c8fa8d74dc2197bd5ef8754e4f3eadb091c743831ad643b7867588c9d0", + "entry_digest": "319c60159eecb9efbd78bb2a137c83b5e0d6357cdb6e72aa96ff86e80a7d3adb", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookDevelopment/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "0efd07ebb2fa2d12769429f782dd1d2d70362adbeca2a82234251c6aa55abe90", + "entry_digest": "a11e80095e0bb66c0baba88236129a1ebef28c54ea2f454e2362c70467a6f960", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookRendering/RookRendering.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3eaeae84bde150f19ca189a04310b28dda74cfb90d55430c8835f07b1ee1008d", + "entry_digest": "65bb892edfa4ca765ffc6556cc977b0af8cd62ccfed702f5c71266ac30debb37", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookRendering/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "9360c435f8fb30b54a7fa3e411a6d8f5347e089ea9038a80734fc821b49dcdcf", + "entry_digest": "17c88752e827fc1622f4a732707fcb86865a43baf1ef6630541f2b0c584f6521", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookSculpture/RookSculpture.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a89be62701494e3b6c7ffbde27888091fe3c0d7d81fb91813fe697686d0381ae", + "entry_digest": "33ea611aec1446b7377f396832436a2f23db9075d8466462a978d6b04554d412", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "apps/sculpt/specs/RookSculpture/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "fddb51105fb11306fc54c53f1c74771fde301812c8a3da5a253108ec89b5000d", + "entry_digest": "3d9dd7140bc5cfe762961be8d7cd0c7fa5369d44dd46ea208384221979a0fa5f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "hi/tools.md", + "kind": "file", + "mode": 33188, + "payload_digest": "cd530f076ed449b2dcd994f9178fcb104f4460e44a12042200b42bf6ca6d6306", + "entry_digest": "a13f216eb32a3671d7563024082ab76eb471bdd7a2ddb3c3398b672b05354a70", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/ThreeMDViewer", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "b53a01354acef7fb830687d9789c70f85c60f43e94da4a2dd0816c771a3bf773", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/ThreeMDViewer.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3b3b09952c692c501a98d6520fb8a82f5126ab9b05d64f6634b50cbae3620ae6", + "entry_digest": "64224b139df2b01fdd0db61c4817d9a836030dbf2667bda60529f6a61be627b4", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "a0011f2d32b7dce6370e015fefcf09acbcf52578e82a97e56def17e0e0fbed52", + "entry_digest": "e020a4426da69e6b24dd3025c95afd9a88cf073bca235f86ad9104e1de81c7f7", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "96612855952a65a5e6b623e2b5d21e9dd8f4ea88c92c0e8ef392e3b826b81f94", + "entry_digest": "5caf30173677b31dcf1119406f03f7dd5a1721487ef58ceacb8d22ed07244d4d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "4b0a856509eb4b4c0c875e4b74844c45ce162acf255ce69bf88f86d82feae603", + "entry_digest": "3767a753d3d8c88a88e61820f68b82317f5cd533b57cec5ddc798c7d33ef2656", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "e224b1bc77ea1679aa4cbd34f182846717be905bec43bff555d19f0ba5f75b15", + "entry_digest": "fee23d7cfc7097bb6cda3f52a2a0efd8ae2030ec4c32059529bccb53252bc7e1", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "uitests/viewer.spec.mjs", + "kind": "file", + "mode": 33188, + "payload_digest": "52dd2553472620fd956815792cb22c70980c8d70ea4563eac487ec5eb4f28093", + "entry_digest": "05c24eeea687cd37e72eaa5382b93877334fb1cb53ab1b80babe625a09d0393b", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "web/viewer.html", + "kind": "file", + "mode": 33188, + "payload_digest": "457af08a02075688bdec1285f820bd6e6ff48e54c392a6239d3a0519a21197b2", + "entry_digest": "91188b507e047ae68fe1e96a1980f5b33206532a2cabafec98e7d7883e0b70e4", + "owners": [ + "ThreeMDViewer" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-007" + ] +} diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json deleted file mode 100644 index 4f72087..0000000 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification-attempts.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "schema_version": 1, - "attempts": [ - { - "timestamp": 1791655587, - "commit": "879ea2515e5a5a9e04ab6672228d9013ae4a4d82", - "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", - "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", - "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-007" - ] - }, - { - "timestamp": 1791655607, - "commit": "3dce9ac0825a9f4c931670540e56d60859249901", - "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", - "execution_digest": "1db450eb32b21efdee8b19e0d917a868a30bbea5a3339a8312faa1e2c95bacb8", - "workspace_digest": "8585efd5a1f8279d68999fda90ab46f7caccdbb47824face80247500c2aef591", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-007" - ] - }, - { - "timestamp": 1791655864, - "commit": "06a806db5100c0b3c0807819bc7c10ad453351e5", - "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", - "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", - "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-007" - ] - }, - { - "timestamp": 1791655884, - "commit": "deb44c9222f5ef7593ad19e3786f31aa26d880c9", - "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", - "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", - "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-007" - ] - } - ] -} diff --git a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json b/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json deleted file mode 100644 index 596a5f0..0000000 --- a/.specsync/changes/add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/verification.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "timestamp": 1791655884, - "commit": "deb44c9222f5ef7593ad19e3786f31aa26d880c9", - "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", - "execution_digest": "da242228adc07b4a8a41fc7d90d24f0e9d3d8dd459769a1a72c8cd55aa49ff8f", - "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-007" - ] -} diff --git a/docs/evidence/viewer-slice/README.md b/docs/evidence/viewer-slice/README.md index 796b652..317a2bf 100644 --- a/docs/evidence/viewer-slice/README.md +++ b/docs/evidence/viewer-slice/README.md @@ -18,6 +18,6 @@ Slice preserves raw non-target text, including CRLF, fractional plane positions, The browser’s supported edit profile is complete common rectangular grids up to 64×64, 256 planes, 4000 occupied cells and 1.5 MiB source, with the native palette and dot/space empties. Structural slice actions, volume resizing and browser 3D painting remain subsequent work. Native storage, formats, library APIs, examples, generated browser bundles and releases are unchanged. -Linux CI verification is complete. Final Trust and lifecycle receipts will be recorded after their current runs complete. Actual reviewer identity is agent:codex. Scope and conditional verified closure were directly authorized by Leif; that does not supply a permitted signature or a human diff review. Existing soft unsigned provenance policy remains intact. +Linux CI verification is complete. Both approved changes passed current verification and supported scoped review/finalization, and are archived under `.specsync/archive/changes/2026-10-10-*`. Closure receipts are `slice-closure.json` and `axis-closure.json`; exact final archive-head Trust and remote CI status are reported in PR #93. Actual reviewer identity is agent:codex. Scope and conditional verified closure were directly authorized by Leif; that does not supply a permitted signature or a human diff review. Existing soft unsigned provenance policy remains intact. Implementation commit: `8e9a0c4`. Pinned Trust 1.2.2 / Fledge 1.7.2 passed (`trust-implementation.log`). Actual unsigned agent:codex record and unchanged policy result are in `attestation-implementation.json` and `provenance-implementation.json`; the strict provenance policy fails for the unsigned/unpermitted reviewer, while Trust’s configured soft mode passes with progressive provenance. No policy was changed. diff --git a/docs/evidence/viewer-slice/axis-closure.json b/docs/evidence/viewer-slice/axis-closure.json new file mode 100644 index 0000000..3d3c08b --- /dev/null +++ b/docs/evidence/viewer-slice/axis-closure.json @@ -0,0 +1,13 @@ +{ + "archived": "/Users/leif/Development/_CorvidLabs/3md-edit-preview/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "contract_digest": "4b6d4eb372c26f296d08a35c4242b772ba7f537d690b3ac81723034860824618", + "finalization_digest": "1225a89a0f4a47068497828dd6ef78edf4902c37edde6c9670427d91af38c098", + "id": "add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer", + "implementation_commit": "60055f7806a4d46964b766672784be45713e3c3a", + "implementation_tree": "9970ef31ab167b4c3429cc3aa17af3651c830918", + "lesson_bundle": "/Users/leif/Development/_CorvidLabs/3md-edit-preview/.specsync/archive/changes/2026-10-10-add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer/lesson-bundle.md", + "next_action": "merge the PR on GitHub", + "ready_for_github_merge": true, + "review_digest": "cf186ff11b71dbf0169c2d3aeaa61edefc6e214954bf82620c6ad53d5759d410", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278" +} diff --git a/docs/evidence/viewer-slice/slice-closure.json b/docs/evidence/viewer-slice/slice-closure.json new file mode 100644 index 0000000..2f0818d --- /dev/null +++ b/docs/evidence/viewer-slice/slice-closure.json @@ -0,0 +1,13 @@ +{ + "archived": "/Users/leif/Development/_CorvidLabs/3md-edit-preview/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "contract_digest": "c0b8195b500e020a9703bb7edd72d722e7f379c81edd26658c5b1473356c2d6f", + "finalization_digest": "0caf17781aef4d755beecc9b6930d254942651a5365545cae8df19c5ed4bee94", + "id": "bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference", + "implementation_commit": "6e8d0bb72dec11684d501cf5cbdc25b2f276b853", + "implementation_tree": "87451f2cfbbdf4b72ad4e767612aa45e91478c81", + "lesson_bundle": "/Users/leif/Development/_CorvidLabs/3md-edit-preview/.specsync/archive/changes/2026-10-10-bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference/lesson-bundle.md", + "next_action": "merge the PR on GitHub", + "ready_for_github_merge": true, + "review_digest": "855b061f32615f8397bb99951a89b1b7d0a691fc1508e574abe41b268a242ca6", + "workspace_digest": "fde013fc78a6110e0c0b88de16f5f6e7522e6561a06c0a5c5fd273d884ed5278" +} diff --git a/specs/ThreeMDViewer/tasks.md b/specs/ThreeMDViewer/tasks.md index eb7168a..9fc3462 100644 --- a/specs/ThreeMDViewer/tasks.md +++ b/specs/ThreeMDViewer/tasks.md @@ -49,4 +49,4 @@ spec: ThreeMDViewer.spec.md - [x] Implement the approved matching axis gizmo and numeric precision controls. - [x] Add the approved browser Slice workspace and shared native/browser edit fixtures. - [x] Verify current macOS browser, Linux CI, native and pinned Trust checks. -- [ ] Complete current Slice and precise-axis lifecycle closure. +- [x] Complete current Slice and precise-axis lifecycle closure with actual agent:codex scoped review. diff --git a/specs/ThreeMDViewer/testing.md b/specs/ThreeMDViewer/testing.md index bd23e9c..c2b8a09 100644 --- a/specs/ThreeMDViewer/testing.md +++ b/specs/ThreeMDViewer/testing.md @@ -48,9 +48,9 @@ The Chromium and WebKit viewer suite covers exact draft restoration, invalid and ## Closure regression coverage -The file-draft test waits beyond the 160ms source-render debounce and checks that slice 1 survives before navigating. The phone keyboard test requires paths in alphabetical order before using End and Enter. The existing phone canvas, control separation, and overflow checks run unchanged at 390 by 844 and 320 by 740. The three original failures were reproduced and the targeted regression checks passed in Linux WebKit 1.61.1. The complete Linux hosted suite passed 190 tests with 8 existing skips in 2.1 minutes; the macOS viewer suite passed all 98 tests in 24.0 seconds. Targeted lifecycle verification, pinned Trust, and closure remain pending. +The file-draft test waits beyond the 160ms source-render debounce and checks that slice 1 survives before navigating. The phone keyboard test requires paths in alphabetical order before using End and Enter. The existing phone canvas, control separation, and overflow checks run unchanged at 390 by 844 and 320 by 740. The three original failures were reproduced and the targeted regression checks passed in Linux WebKit 1.61.1. The complete Linux hosted suite passed 190 tests with 8 existing skips in 2.1 minutes; the macOS viewer suite passed all 98 tests in 24.0 seconds. These are historical pre-closure results; the original viewer closure subsequently passed as recorded in the archived change. -Closure implementation checks: macOS viewer 98 passed; Linux hosted UI 190 passed and 8 existing skips; Bun helper suite 15 passed; strict SpecSync 4 specs passed with zero warnings and full configured coverage; Hi 85 criteria with no problems; pinned element bundle drift passed at 48840 bytes. Logs remain local under /private/tmp/3md-viewer-closure-*. The Trust and SpecSync closing gates are still pending. +Closure implementation checks: macOS viewer 98 passed; Linux hosted UI 190 passed and 8 existing skips; Bun helper suite 15 passed; strict SpecSync 4 specs passed with zero warnings and full configured coverage; Hi 85 criteria with no problems; pinned element bundle drift passed at 48840 bytes. Logs remain local under /private/tmp/3md-viewer-closure-*. These historical checks preceded the original viewer and camera archives. Current Slice/axis checks are listed below. ## Full camera parity @@ -68,3 +68,5 @@ The volume camera shows colored X/Y/Z rings and Free/X/Y/Z constraints. A normal ## Current approved Slice and precise-axis verification 2026-10-10: complete macOS UI 226 passed without skips or retries; Linux CI UI 218 passed with 8 existing platform-snapshot skips and no retries; configured native suite 637 passed and final parity selection 11 passed. Shared fixtures compare native workspace edits and actual browser gestures against independent expected rows and camera matrices. Logs and actual UI screenshots are in `docs/evidence/viewer-slice/`. Pinned Trust passed for implementation commit `8e9a0c4`; final archive-tip verification remains separate. Actual unsigned agent:codex provenance is recorded and does not satisfy the unchanged strict permitted-signature/reviewer policy. + +Both current approved changes were successfully finalized and archived on 2026-10-10. Their supported scoped review records identify agent:codex. Scope authorization and agent verification do not claim independent human review or a permitted signature. Exact final archive-head Trust and remote CI status are reported in PR #93; the implementation and test fixtures are unchanged from `8e9a0c4`. From 95c1213886b853a7b945fd833a5af02fa0f8128d Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:40:42 -0600 Subject: [PATCH 39/43] Fix shared 3D canvas resolution after Slice and display changes --- .../approvals.json | 42 + .../change.md | 24 + .../context.md | 10 + .../deltas/ThreeMDViewer.md | 15 + .../state.json | 38 + .../tasks.md | 13 + .../testing.md | 18 + docs/evidence/viewer-resolution/README.md | 20 + .../viewer-resolution/browser-after.png | Bin 0 -> 125077 bytes .../viewer-resolution/browser-before.png | Bin 0 -> 91719 bytes .../viewer-resolution/browser-full.log | 1926 +++++++++++++++++ .../viewer-resolution/density-final.log | 53 + .../viewer-resolution/viewer-final.log | 1385 ++++++++++++ specs/ThreeMDViewer/ThreeMDViewer.spec.md | 5 +- specs/ThreeMDViewer/context.md | 6 +- specs/ThreeMDViewer/testing.md | 6 + uitests/viewer.spec.mjs | 81 + web/viewer.html | 24 +- 18 files changed, 3654 insertions(+), 12 deletions(-) create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md create mode 100644 docs/evidence/viewer-resolution/README.md create mode 100644 docs/evidence/viewer-resolution/browser-after.png create mode 100644 docs/evidence/viewer-resolution/browser-before.png create mode 100644 docs/evidence/viewer-resolution/browser-full.log create mode 100644 docs/evidence/viewer-resolution/density-final.log create mode 100644 docs/evidence/viewer-resolution/viewer-final.log diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json new file mode 100644 index 0000000..e6ae11d --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json @@ -0,0 +1,42 @@ +{ + "approvals": [ + { + "gate": "definition", + "actor": "agent:codex", + "timestamp": 1791656803, + "digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "note": "Codex records the narrow corrective scope under Leif’s standing direct authorization to keep improving browser/Sculpt parity and fix PR 93, prompted by the current blur report. This applies existing repair authority; it is not a claim of a new human definition review, Leif diff review, independent review or signature.", + "approved_scope": { + "schema_version": 1, + "change_id": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "title": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", + "description": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", + "kind": "bug_fix", + "affected_specs": [ + "ThreeMDViewer" + ], + "affected_paths": [ + "docs/evidence/viewer-resolution", + "specs/ThreeMDViewer", + "uitests/viewer.spec.mjs", + "web/viewer.html" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "The shared 3D canvas drawing buffer follows the displayed Cubes or Slice-reference size and device pixel ratio within the existing 2048-edge/2x limits; switching from a small reference or phone viewport to a large stage remains sharp; resizing retains the same WebGL context, geometry and camera/source/selection; Chromium, WebKit and the actual in-app browser verify transitions and picking." + ], + "dependencies": [], + "supersedes": [], + "answers": { + "architecture_risk": "no", + "public_contract": "no" + } + }, + "approved_delta_digests": { + "ThreeMDViewer": "77b5cd3341a46906bd1c09ba7e2e6c3bff2aa8f9c8e30c453b632c680c52fed9" + } + } + ], + "reopenings": [] +} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md new file mode 100644 index 0000000..f1590ae --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md @@ -0,0 +1,24 @@ +--- +id: repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera +state: implementing +type: bug_fix +base_commit: dab4258541208f8bf6bb5a38f6200a5b348a858e +--- + +# Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity + +## Intent + +Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity + +## Affected Canonical Specs + +- `ThreeMDViewer` + +## Acceptance Criteria + +- The shared 3D canvas drawing buffer follows the displayed Cubes or Slice-reference size and device pixel ratio within the existing 2048-edge/2x limits; switching from a small reference or phone viewport to a large stage remains sharp; resizing retains the same WebGL context, geometry and camera/source/selection; Chromium, WebKit and the actual in-app browser verify transitions and picking. + +## No-spec Rationale + +Not applicable diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md new file mode 100644 index 0000000..616d215 --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md @@ -0,0 +1,10 @@ +--- +change: repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera +artifact: context +--- + +# Context + +Leif reported the existing browser preview was blurry after the approved Slice/camera work. Actual DOM and screenshot inspection found the shared 3D canvas bitmap at 368x322 while its Cubes display was 1099x911. The bitmap was frozen after initial context creation as a Safari workaround; a phone/reference-sized initialization was later stretched across a desktop stage. + +This repairs the existing approved viewer/Sculpt-quality behavior under Leif's standing request to continue improving the browser and fix the viewer PR. It adds no editing tool, storage behavior, renderer or camera convention. Preserve the single WebGL context, installed mesh, source, selection, pose, 2x density cap and 2048 pixel edge cap. Resize only the drawable when its required dimensions change; validate actual in-app WebKit behavior rather than assuming every resize loses its context. diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md new file mode 100644 index 0000000..6cfca25 --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md @@ -0,0 +1,15 @@ +# ThreeMDViewer delta + +## MODIFIED + +### REQUIREMENT REQ-ThreeMDViewer-004 + +The viewer page SHALL NOT offer a render-mode switch and SHALL NOT autoplay. Preview SHALL stay on one plane. Cubes SHALL draw complete, nearly cell-sized cubes with WebGL2, lit glyph-colored fill at 0.5 opacity and visible glyph-colored edges. The selected Z slice SHALL have gold edges at 0.8 opacity while retaining its glyph fill. The background SHALL be rgb(0.065, 0.085, 0.10). X SHALL be the column, Y the text row with row 0 toward the top, and Z the plane index. Orbit, zoom, and slice selection SHALL reuse the installed geometry. Each redraw SHALL use one instanced draw. Orbit SHALL rotate through full horizontal and vertical turns with a continuous camera basis at the poles. Pan mode, Shift-drag, and middle/right-drag SHALL move the view in screen space. Shift-arrow keys SHALL pan the focused canvas. Two-finger touch gestures SHALL pan and pinch to zoom. Wheel zoom SHALL respond proportionally to the gesture. Fit SHALL restore yaw 0.6, pitch 0.35, zoom 1, and zero pan without changing source or the selected slice. Camera buttons and the focused canvas SHALL support bounded zoom, and arrow keys SHALL orbit the focused canvas. Camera controls SHALL sit below the drawing without covering cubes. A document without a cube grid and an unavailable WebGL2 context SHALL offer Preview while preserving the source. The element bundle SHALL stay a text renderer. + +Acceptance Criteria: + +- The page has no render-mode menu and no page play control. A frame-axis document is not playing. +- A fenced grid draws on WebGL2, including about 1400 cubes. A single cell has filled faces from every side. Selection changes edge color while the face interior keeps its glyph color. Camera, zoom, and selection redraw without geometry uploads. Click picking selects the nearest visible cube’s Z slice. +- X is the column, Y is the text row with row 0 toward the top, and Z is the plane index. Space, dot, and tab are empty. Keep the 64 by 64 per-plane and 4000-cell caps. +- Evidence is VIEWER-6 and the cube tests in `uitests/viewer.spec.mjs`. +- The same 3D context and geometry remain installed when moving between Cubes and the Slice reference or changing display size. The drawable follows the visible pane size and device pixel ratio, bounded to 2x and a proportional 2048-pixel edge cap; unchanged sizes avoid bitmap reallocations. Small-to-large, phone/desktop and Retina transitions remain sharp without changing source, camera, slice or nearest picking. diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json new file mode 100644 index 0000000..453349d --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json @@ -0,0 +1,38 @@ +{ + "schema_version": 1, + "workflow_version": 2, + "workflow_origin_version": 2, + "id": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "slug": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "title": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", + "description": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", + "kind": "bug_fix", + "state": "implementing", + "base_commit": "dab4258541208f8bf6bb5a38f6200a5b348a858e", + "created_at": 1791656681, + "updated_at": 1791656808, + "affected_specs": [ + "ThreeMDViewer" + ], + "affected_paths": [ + "web/viewer.html", + "uitests/viewer.spec.mjs", + "specs/ThreeMDViewer", + "docs/evidence/viewer-resolution" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "The shared 3D canvas drawing buffer follows the displayed Cubes or Slice-reference size and device pixel ratio within the existing 2048-edge/2x limits; switching from a small reference or phone viewport to a large stage remains sharp; resizing retains the same WebGL context, geometry and camera/source/selection; Chromium, WebKit and the actual in-app browser verify transitions and picking." + ], + "selected_artifacts": [ + "context", + "testing", + "tasks" + ], + "dependencies": [], + "answers": { + "architecture_risk": "no", + "public_contract": "no" + } +} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md new file mode 100644 index 0000000..1c413ed --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md @@ -0,0 +1,13 @@ +--- +change: repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera +artifact: tasks +--- + +# Tasks + +- [x] Reproduce the reported blur and measure bitmap/display dimensions. +- [x] Define the bounded corrective repair under existing browser quality authority. +- [x] Make the shared 3D drawable follow visible pane and display density. +- [x] Verify Chromium/WebKit small-to-large, Slice/Cubes, desktop/phone and Retina transitions with one retained context and no geometry uploads. +- [x] Inspect sharp output in the actual in-app browser without losing Leif's edited draft. +- [ ] Synchronize implementation notes, run strict specs and pinned Trust, and record actual provenance. diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md new file mode 100644 index 0000000..dfba0cb --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md @@ -0,0 +1,18 @@ +--- +change: repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera +artifact: testing +--- + +# Testing + +At device pixel ratios 1 and 2, initialize a phone-sized Cubes stage, switch through Slice's small reference and expand/resize to desktop and larger-than-cap layouts. Check actual drawable width/height against proportional 2048-edge/2x bounds, the same context/program/mesh, zero context-loss events and zero subsequent geometry uploads. Preserve source, selected slice, camera pose and nearest picking. Run existing projection, pixel, Slice and navigation regressions on Chromium and WebKit and inspect the actual in-app WebKit output. Root strict specs and pinned Trust must pass; actual unsigned agent:codex provenance remains separate from a permitted signature or human diff review. + +## Requirement evidence + +| ID | Canonical | Evidence | +| --- | --- | --- | +| REQ-ThreeMDViewer-004 | REQ-ThreeMDViewer-004 | New actual drawable-density and context-retention regression, existing GPU pixel/projection/picking tests, in-app browser before/after measurements and screenshot. | + +## Current results + +The complete post-resize UI suite passed 230 tests. After final display-density listeners, the viewer suite passed 130 tests. The final media-query/window-resize density regressions passed 4 tests. All ran on Chromium and WebKit without skips or retries. Actual in-app bitmap/display measurements and screenshots, test logs and implementation digests are in `docs/evidence/viewer-resolution/`. Pinned Trust, actual provenance and finalization remain separately evidenced. diff --git a/docs/evidence/viewer-resolution/README.md b/docs/evidence/viewer-resolution/README.md new file mode 100644 index 0000000..aad18cc --- /dev/null +++ b/docs/evidence/viewer-resolution/README.md @@ -0,0 +1,20 @@ +# Shared 3D drawable resolution repair + +Leif reported a blurry Cubes stage after Slice/camera work. Actual in-app WebKit measurement found a 368x322 drawing bitmap displayed at 1099x911 at density 1. The previous Safari workaround froze bitmap dimensions after context creation; expanding the small reference/phone view stretched that bitmap. + +The fix updates only changed drawable dimensions, retains the existing context/program/geometry and redraws the current camera. The proportional 2048-edge and 2x density limits remain. Window resize and a rearmed resolution media query cover display changes, including density changes without a CSS-size change. No native source, format, camera convention or storage behavior changes. + +## Verification + +- Complete macOS Chromium/WebKit UI after the resize repair: 230 passed, no skips or retries (`browser-full.log`). This preceded the final density-change listeners. +- Complete final viewer suite after the density-change listeners: 130 passed, no skips or retries (`viewer-final.log`). +- Final density regressions, including the rearmed media-query callback and window-resize fallback: 4 passed, no skips or retries (`density-final.log`). +- At initial 1x/2x density, the new tests cover phone-to-desktop, small Slice reference, expanded Cubes, repeated view switches and larger-than-cap layouts. They compare actual WebGL drawing-buffer dimensions, retain one context/program with zero losses or geometry uploads/allocations, and preserve source, selected plane and pose. Existing projection, nearest picking and GPU pixel tests passed in the viewer suite. +- Actual user draft was preserved in its original tab. A separate preview copied its current 134-cell source. At the same 1099x911 displayed size, the repaired bitmap measured 1099x911 with WebGL2 active. The small reference measured 199x170 and the expanded stage 990x333, each matching its bitmap. Actual before/after frames are `browser-before.png` and `browser-after.png`; the before/after camera framing differs, so this is resolution evidence rather than a pixel-equality comparison. + +Native behavior was already verified in `../viewer-slice/`; it is unchanged by this repair. Repository Trust and lifecycle results are recorded separately after the implementation commit. Agent verification does not claim Leif reviewed this diff, independent human review or a permitted signature. Existing Trust/provenance policy remains unchanged. + +## Verified implementation content + +- `web/viewer.html`: `d5c226e7ccb6b46c7e462c6d72a89772138080dce9269f0813cd0979d10116b8` +- `uitests/viewer.spec.mjs`: `59894ffd439caff704f34d3fba39425e991f854fcfe83a73aca673b0883c1c97` diff --git a/docs/evidence/viewer-resolution/browser-after.png b/docs/evidence/viewer-resolution/browser-after.png new file mode 100644 index 0000000000000000000000000000000000000000..de38bb5dbdc8c25558885aee67a86430a6a82dce GIT binary patch literal 125077 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
!&Jxi(+f=LQ;iTf{t61&VlUzxbb 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 z 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
`_bK@zc-oEVH5_-;1Etpw_%-B)gZZD;}# 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�b7~DqUwQ1(7CYdM-vB0OD5^ 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 Gd;beHnB%Gd literal 0 HcmV?d00001 diff --git a/docs/evidence/viewer-resolution/browser-full.log b/docs/evidence/viewer-resolution/browser-full.log new file mode 100644 index 0000000..f7e82df --- /dev/null +++ b/docs/evidence/viewer-resolution/browser-full.log @@ -0,0 +1,1926 @@ + +Running 230 tests using 2 workers + +(node:76552) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +(node:76553) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /sample.3md HTTP/1.1" 200 - + ✓ 2 [chromium] › component.spec.mjs:53:3 › component › all deck cards share one width (focused matches the cards behind it) (148ms) + ✓ 1 [chromium] › component.spec.mjs:35:3 › component › upgrades, renders planes, no console errors (149ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /sample.3md HTTP/1.1" 200 - + ✓ 3 [chromium] › component.spec.mjs:69:3 › component › wide ASCII-art content is not clipped (card widens to fit rigid blocks) (96ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /sample.3md HTTP/1.1" 200 - + ✓ 4 [chromium] › component.spec.mjs:84:3 › component › focused plane is frontmost across the scrubber (691ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:46] "GET /sample.3md HTTP/1.1" 200 - + ✓ 6 [chromium] › component.spec.mjs:109:3 › component › no horizontal overflow from 320px to 1440px (178ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:47] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:47] "GET /sample.3md HTTP/1.1" 200 - + ✓ 7 [chromium] › component.spec.mjs:123:3 › component › playback advances and pauses (animations) (2.4s) +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /sample.3md HTTP/1.1" 200 - + ✓ 8 [chromium] › component.spec.mjs:139:3 › component › frame animations render as a flipbook (one frame, no deck) and autoplay (100ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /sample.3md HTTP/1.1" 200 - + ✓ 9 [chromium] › component.spec.mjs:160:3 › component › does not auto-convert characters; an optional legend maps them (94ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /sample.3md HTTP/1.1" 200 - + ✓ 10 [chromium] › component.spec.mjs:184:3 › component › camera: WASD/wheel/orbit move the scene; retired modes alias (91ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /sample.3md HTTP/1.1" 200 - + ✓ 11 [chromium] › component.spec.mjs:210:3 › component › map mode lays planes out by x/y (90ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /sample.3md HTTP/1.1" 200 - + ✓ 12 [chromium] › component.spec.mjs:223:3 › component › renders Markdown tables (not raw pipes) (89ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:49] "GET /sample.3md HTTP/1.1" 200 - + ✓ 13 [chromium] › component.spec.mjs:239:3 › component › layers shows aligned overlays at once, with toggle chips (87ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 14 [chromium] › component.spec.mjs:261:3 › component › blend mode renders content as 3D voxels (86ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 15 [chromium] › component.spec.mjs:281:3 › component › single-card mode shows only the focused plane (225ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 16 [chromium] › component.spec.mjs:303:3 › component › single-card mode scrolls a long plane (reader) (93ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 17 [chromium] › component.spec.mjs:326:3 › component › reflects the resolved mode as data-mode (for fullscreen styling) (90ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 18 [chromium] › component.spec.mjs:343:3 › component › space and PageDown advance like a slideshow (not in reader) (96ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 19 [chromium] › component.spec.mjs:366:3 › component › cross-plane links [[z=N|text]] are clickable and navigate (87ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 20 [chromium] › component.spec.mjs:383:3 › component › a tap (pointer, no drag) on a cross-plane link navigates (88ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 21 [chromium] › component.spec.mjs:402:3 › component › flipbook frames are a fixed size (no resize between frames) (95ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:50] "GET /sample.3md HTTP/1.1" 200 - + ✓ 22 [chromium] › component.spec.mjs:420:3 › component › loop toggle controls whether playback wraps (99ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 23 [chromium] › component.spec.mjs:438:3 › component › emits planechange when stepping (85ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 24 [chromium] › component.spec.mjs:450:3 › component › legend values cannot inject HTML (XSS sink is escaped) (281ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 25 [chromium] › component.spec.mjs:485:3 › component › cross-plane links work for decimal z (not just integers) (87ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 26 [chromium] › component.spec.mjs:503:3 › component › switching into blend after load builds voxels (no empty stage) (268ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 27 [chromium] › component.spec.mjs:518:3 › component › blend voxels are the legend-mapped character glyphs, and billboard faces the camera (85ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 28 [chromium] › component.spec.mjs:537:3 › component › without a legend, blend voxels show the raw characters (87ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 29 [chromium] › component.spec.mjs:549:3 › component › blend is gated to COMPACT art: a sprawling grid is not voxelizable (falls back to deck) (85ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 30 [chromium] › component.spec.mjs:571:3 › component › map and layers keep every tile inside the stage on all edges (many tiles) (93ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 31 [chromium] › component.spec.mjs:598:3 › component › map orbit is clamped so an extreme pose never spills a tile off the stage (87ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 32 [chromium] › component.spec.mjs:623:3 › component › map snaps coordinates to a non-overlapping grid (same x = column, same y = row) (84ms) + ✓ 5 [chromium] › component.spec.mjs:94:3 › component › works with requestAnimationFrame paused (Low Power Mode) (6.1s) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 33 [chromium] › component.spec.mjs:652:3 › component › map: no-coordinate planes lay out in a clean non-overlapping grid (98ms) + ✓ 34 [chromium] › component.spec.mjs:672:3 › component › map: the focused card pops to a larger readable size than the board tiles (92ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 35 [chromium] › component.spec.mjs:689:3 › component › map opens on a full-board overview (nothing forced open) until a tile is opened (95ms) + ✓ 36 [chromium] › component.spec.mjs:711:3 › component › map: partially-positioned planes (only x or only y) do not pile up (92ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 37 [chromium] › component.spec.mjs:728:3 › component › map: unpositioned planes do not collapse onto explicit (0,0) (102ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:53] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 39 [chromium] › lab.spec.mjs:59:3 › lab demo (index.html, backed by ) › renders via the component with no console errors (768ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:53] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:53] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 38 [chromium] › examples-coverage.spec.mjs:8:1 › the component renders every gallery example cleanly (1.9s) +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 40 [chromium] › lab.spec.mjs:69:3 › lab demo (index.html, backed by ) › focused plane is frontmost across the scrubber (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:55] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 42 [chromium] › lab.spec.mjs:92:3 › lab demo (index.html, backed by ) › no horizontal overflow from 320px to 1440px (783ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:55] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:55] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:55] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 43 [chromium] › lab.spec.mjs:102:3 › lab demo (index.html, backed by ) › stepping the component highlights the synced source (927ms) +[WebServer] ::1 - - [10/Oct/2026 12:30:56] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:56] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:56] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:56] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:56] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 41 [chromium] › lab.spec.mjs:75:3 › lab demo (index.html, backed by ) › every axis tab loads, scrubs cleanly, and syncs the source panel (5.1s) +[WebServer] ::1 - - [10/Oct/2026 12:30:59] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:59] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:59] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:59] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:30:59] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 44 [chromium] › robustness.spec.mjs:37:3 › robustness (no degradation under heavy use) › no rAF-loop accumulation after switching tabs many times (3.8s) +[WebServer] ::1 - - [10/Oct/2026 12:31:00] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:00] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:00] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:00] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:00] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 46 [chromium] › robustness.spec.mjs:95:3 › robustness (no degradation under heavy use) › rapid play/pause and scrub leave no timers or errors (2.2s) +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 45 [chromium] › robustness.spec.mjs:65:3 › robustness (no degradation under heavy use) › DOM does not grow and the renderer stays correct after heavy use (3.4s) +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:03] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 47 [chromium] › snapshots.spec.mjs:37:3 › stage snapshot: stack (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:31:03] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:03] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:03] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 48 [chromium] › snapshots.spec.mjs:37:3 › stage snapshot: layers (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 49 [chromium] › snapshots.spec.mjs:37:3 › stage snapshot: scene (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:04] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 50 [chromium] › snapshots.spec.mjs:37:3 › stage snapshot: present (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 51 [chromium] › viewer.spec.mjs:34:3 › viewer & editor (viewer.html) › opening the page shows lit cubes in the window (637ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 52 [chromium] › viewer.spec.mjs:78:3 › viewer & editor (viewer.html) › one cell has filled faces from every side, with gold edges and glyph fill (804ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:05] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 53 [chromium] › viewer.spec.mjs:152:3 › viewer & editor (viewer.html) › clicking a visible cube picks its Z slice and blank stage does not (743ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 54 [chromium] › viewer.spec.mjs:165:3 › viewer & editor (viewer.html) › renders the starter document with no console errors (618ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:06] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 55 [chromium] › viewer.spec.mjs:176:3 › viewer & editor (viewer.html) › editing the source re-renders live (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 56 [chromium] › viewer.spec.mjs:190:3 › viewer & editor (viewer.html) › invalid 3md shows an error without crashing (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:07] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 57 [chromium] › viewer.spec.mjs:204:3 › viewer & editor (viewer.html) › loading an example populates the editor and viewer (1.3s) + ✓ 58 [chromium] › viewer.spec.mjs:218:3 › viewer & editor (viewer.html) › editor highlights syntax and numbers every line (703ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:08] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 59 [chromium] › viewer.spec.mjs:246:3 › viewer & editor (viewer.html) › Tab indents and Enter continues a list (699ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 60 [chromium] › viewer.spec.mjs:262:3 › viewer & editor (viewer.html) › clicking a plane outline chip focuses that plane (982ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 61 [chromium] › viewer.spec.mjs:273:3 › viewer & editor (viewer.html) › the highlight backdrop scrolls with the textarea (tall document) (750ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 62 [chromium] › viewer.spec.mjs:290:3 › viewer & editor (viewer.html) › smart-key edits are undoable and never corrupt the buffer (792ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 63 [chromium] › viewer.spec.mjs:311:3 › viewer & editor (viewer.html) › validity state is machine-readable via data attributes (967ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:10] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 64 [chromium] › viewer.spec.mjs:337:3 › viewer & editor (viewer.html) › Tab does not trap keyboard focus (Esc then Tab leaves the editor) (866ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 65 [chromium] › viewer.spec.mjs:351:3 › viewer & editor (viewer.html) › agent API validates and reports structured state (670ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 66 [chromium] › viewer.spec.mjs:364:3 › viewer & editor (viewer.html) › validate(src) is side-effect-free and reports the error code (648ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:11] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 67 [chromium] › viewer.spec.mjs:380:3 › viewer & editor (viewer.html) › repository search opens the 24-generation Conway document (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 68 [chromium] › viewer.spec.mjs:395:3 › viewer & editor (viewer.html) › kind 2 canopy opens as text in the element (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:12] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 69 [chromium] › viewer.spec.mjs:412:3 › viewer & editor (viewer.html) › linked village search resolves the folder (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 70 [chromium] › viewer.spec.mjs:426:3 › viewer & editor (viewer.html) › a composition profile shows the root and can switch entries (1.5s) +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:14] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 72 [chromium] › viewer.spec.mjs:458:3 › viewer & editor (viewer.html) › desktop layout keeps files beside a panel that switches Edit and Preview (913ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /viewer.html HTTP/1.1" 200 - + ✓ 71 [chromium] › viewer.spec.mjs:441:3 › viewer & editor (viewer.html) › markdown headings become planes and a plane search opens one (1.4s) +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:15] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 74 [chromium] › viewer.spec.mjs:546:3 › viewer & editor (viewer.html) › orbiting about 1400 gpu cubes stays interactive (787ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 73 [chromium] › viewer.spec.mjs:514:3 › viewer & editor (viewer.html) › cubes tab draws a fenced grid as translucent cubes (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:16] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 76 [chromium] › viewer.spec.mjs:627:3 › viewer & editor (viewer.html) › an empty document reads as a neutral prompt, not a red error (995ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 75 [chromium] › viewer.spec.mjs:591:3 › viewer & editor (viewer.html) › narrow layout switches Files and the document, and Edit and Preview still switch (1.5s) +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:17] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 77 [chromium] › viewer.spec.mjs:645:3 › viewer & editor (viewer.html) › axis lint warns on a TYPO but not on a valid free-string semantic axis (740ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 78 [chromium] › viewer.spec.mjs:671:3 › viewer & editor (viewer.html) › the page has no render-mode switch and does not autoplay (744ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 79 [chromium] › viewer.spec.mjs:692:3 › viewer & editor (viewer.html) › the agent schema lists error codes and the axis-to-mode map (634ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 80 [chromium] › viewer.spec.mjs:702:3 › viewer & editor (viewer.html) › dangling cross-plane links are flagged as a non-fatal warning (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 81 [chromium] › viewer.spec.mjs:713:3 › viewer & editor (viewer.html) › a corrupt share hash signals a decode error (not a silent starter) (915ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:19] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 82 [chromium] › viewer.spec.mjs:722:3 › viewer & editor (viewer.html) › the embedded agent schema marks axis optional, only 3md required (713ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 83 [chromium] › viewer.spec.mjs:729:3 › viewer & editor (viewer.html) › invalid doc clears stale plane/axis data on the badge (979ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:20] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 84 [chromium] › viewer.spec.mjs:742:3 › viewer & editor (viewer.html) › an invalid document flags the offending line and the badge (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 85 [chromium] › viewer.spec.mjs:755:3 › viewer & editor (viewer.html) › a shared hash link restores the document (681ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:21] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 86 [chromium] › viewer.spec.mjs:766:3 › viewer & editor (viewer.html) › camera buttons and keyboard orbit, zoom, and fit without changing the document (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 87 [chromium] › viewer.spec.mjs:795:3 › viewer & editor (viewer.html) › full camera turns cross both poles continuously and retain geometry (774ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 88 [chromium] › viewer.spec.mjs:843:3 › viewer & editor (viewer.html) › pan tools and modified dragging move only the camera and Fit recenters (835ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 89 [chromium] › viewer.spec.mjs:874:3 › viewer & editor (viewer.html) › two fingers pan and pinch and a cancelled gesture cannot select a slice (798ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 91 [chromium] › viewer.spec.mjs:965:3 › viewer & editor (viewer.html) › phone layout leaves room for cubes and keeps controls outside the drawing (828ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 92 [chromium] › viewer.spec.mjs:987:3 › viewer & editor (viewer.html) › Document disclosure dismisses with Escape and both downloads preserve the document (942ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 93 [chromium] › viewer.spec.mjs:1024:3 › viewer & editor (viewer.html) › a prose document offers Preview without replacing its source (872ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:25] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 94 [chromium] › viewer.spec.mjs:1042:3 › viewer & editor (viewer.html) › slice navigation keeps the selected plane in a single scrolling row (737ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 90 [chromium] › viewer.spec.mjs:897:3 › viewer & editor (viewer.html) › browser camera projects and picks the shared native parity fixture (3.6s) +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:26] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 96 [chromium] › viewer.spec.mjs:1084:3 › viewer & editor (viewer.html) › GPU unavailability explains how to keep reading in Preview (717ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 95 [chromium] › viewer.spec.mjs:1064:3 › viewer & editor (viewer.html) › a GitHub load shows busy state and recovers after a rate limit (858ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:27] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 98 [chromium] › viewer.spec.mjs:1143:3 › viewer & editor (viewer.html) › composition entry switches preserve each draft without copying it into another entry (813ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 97 [chromium] › viewer.spec.mjs:1100:3 › viewer & editor (viewer.html) › file switches preserve edited, invalid, and empty drafts with caret and slice (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:28] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 99 [chromium] › viewer.spec.mjs:1170:3 › viewer & editor (viewer.html) › linked entries and file navigation share the same draft (854ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 100 [chromium] › viewer.spec.mjs:1195:3 › viewer & editor (viewer.html) › search and packing use drafts rather than original file text (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 101 [chromium] › viewer.spec.mjs:1212:3 › viewer & editor (viewer.html) › file filtering, keyboard selection, and phone opens reveal the document (912ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /viewer.html?src=original-document.3md&theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 102 [chromium] › viewer.spec.mjs:1240:3 › viewer & editor (viewer.html) › a failed local open preserves the collection and current draft (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 103 [chromium] › viewer.spec.mjs:1259:3 › viewer & editor (viewer.html) › explicit document navigation removes stale source queries and reloads the chosen source (1.6s) +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:31] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 105 [chromium] › viewer.spec.mjs:1316:3 › Sculpt Slice parity › grid edits preserve CRLF, labels, prose and downloads exactly (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:32] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 106 [chromium] › viewer.spec.mjs:1328:3 › Sculpt Slice parity › keyboard cells, grid zoom, previous overlay and shared WebGL reference (903ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 104 [chromium] › viewer.spec.mjs:1298:3 › Sculpt Slice parity › shared native strokes, clipped brushes, four-neighbor fill and no-op undo (3.1s) +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:33] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 107 [chromium] › viewer.spec.mjs:1341:3 › Sculpt Slice parity › source typing and Slice share undo and retain it across file navigation (963ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:34] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 108 [chromium] › viewer.spec.mjs:1353:3 › Sculpt Slice parity › unsupported grids stay readable and budget rejection restores the full stroke (1.8s) + ✓ 109 [chromium] › viewer.spec.mjs:1361:3 › Sculpt Slice parity › phone Slice tools and axis controls stay usable without horizontal page overflow (995ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:35] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 110 [chromium] › viewer.spec.mjs:1370:3 › Sculpt Slice parity › 2D editing works with an unavailable WebGL reference (737ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 111 [chromium] › viewer.spec.mjs:1375:3 › Sculpt Slice parity › axis inverse, finite inputs, pan steps and Fit leave source and geometry intact (872ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:36] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 113 [chromium] › viewer.spec.mjs:1411:1 › Slice navigation finishes a touch stroke and ignores its late pointer movement (851ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:37] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 114 [chromium] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 1x density (2.4s) +[WebServer] ::1 - - [10/Oct/2026 12:31:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:40] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:40] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:40] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 115 [chromium] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 2x density (2.7s) + ✓ 112 [chromium] › viewer.spec.mjs:1389:1 › Slice history drops only old snapshots at the per-draft and collection budgets (6.3s) +(node:76965) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +(node:76967) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:43] "GET /sample.3md HTTP/1.1" 200 - + ✓ 117 [webkit] › component.spec.mjs:53:3 › component › all deck cards share one width (focused matches the cards behind it) (791ms) + ✓ 116 [webkit] › component.spec.mjs:35:3 › component › upgrades, renders planes, no console errors (811ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /sample.3md HTTP/1.1" 200 - + ✓ 119 [webkit] › component.spec.mjs:84:3 › component › focused plane is frontmost across the scrubber (820ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:44] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:47] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:47] "GET /sample.3md HTTP/1.1" 200 - + ✓ 118 [webkit] › component.spec.mjs:69:3 › component › wide ASCII-art content is not clipped (card widens to fit rigid blocks) (3.6s) +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - + ✓ 120 [webkit] › component.spec.mjs:94:3 › component › works with requestAnimationFrame paused (Low Power Mode) (6.3s) +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 121 [webkit] › component.spec.mjs:109:3 › component › no horizontal overflow from 320px to 1440px (3.7s) +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 123 [webkit] › component.spec.mjs:139:3 › component › frame animations render as a flipbook (one frame, no deck) and autoplay (277ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 124 [webkit] › component.spec.mjs:160:3 › component › does not auto-convert characters; an optional legend maps them (271ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:51] "GET /sample.3md HTTP/1.1" 200 - + ✓ 125 [webkit] › component.spec.mjs:184:3 › component › camera: WASD/wheel/orbit move the scene; retired modes alias (277ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 126 [webkit] › component.spec.mjs:210:3 › component › map mode lays planes out by x/y (278ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 127 [webkit] › component.spec.mjs:223:3 › component › renders Markdown tables (not raw pipes) (269ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:52] "GET /sample.3md HTTP/1.1" 200 - + ✓ 128 [webkit] › component.spec.mjs:239:3 › component › layers shows aligned overlays at once, with toggle chips (266ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /sample.3md HTTP/1.1" 200 - + ✓ 129 [webkit] › component.spec.mjs:261:3 › component › blend mode renders content as 3D voxels (273ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /sample.3md HTTP/1.1" 200 - + ✓ 130 [webkit] › component.spec.mjs:281:3 › component › single-card mode shows only the focused plane (385ms) + ✓ 122 [webkit] › component.spec.mjs:123:3 › component › playback advances and pauses (animations) (2.6s) +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /sample.3md HTTP/1.1" 200 - + ✓ 131 [webkit] › component.spec.mjs:303:3 › component › single-card mode scrolls a long plane (reader) (279ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:53] "GET /sample.3md HTTP/1.1" 200 - + ✓ 132 [webkit] › component.spec.mjs:326:3 › component › reflects the resolved mode as data-mode (for fullscreen styling) (272ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /sample.3md HTTP/1.1" 200 - + ✓ 133 [webkit] › component.spec.mjs:343:3 › component › space and PageDown advance like a slideshow (not in reader) (266ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /sample.3md HTTP/1.1" 200 - + ✓ 134 [webkit] › component.spec.mjs:366:3 › component › cross-plane links [[z=N|text]] are clickable and navigate (273ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /sample.3md HTTP/1.1" 200 - + ✓ 136 [webkit] › component.spec.mjs:402:3 › component › flipbook frames are a fixed size (no resize between frames) (271ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /sample.3md HTTP/1.1" 200 - + ✓ 137 [webkit] › component.spec.mjs:420:3 › component › loop toggle controls whether playback wraps (282ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:54] "GET /sample.3md HTTP/1.1" 200 - + ✓ 138 [webkit] › component.spec.mjs:438:3 › component › emits planechange when stepping (259ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /sample.3md HTTP/1.1" 200 - + ✓ 139 [webkit] › component.spec.mjs:450:3 › component › legend values cannot inject HTML (XSS sink is escaped) (445ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /sample.3md HTTP/1.1" 200 - + ✓ 140 [webkit] › component.spec.mjs:485:3 › component › cross-plane links work for decimal z (not just integers) (268ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:55] "GET /sample.3md HTTP/1.1" 200 - + ✓ 141 [webkit] › component.spec.mjs:503:3 › component › switching into blend after load builds voxels (no empty stage) (448ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /sample.3md HTTP/1.1" 200 - + ✓ 142 [webkit] › component.spec.mjs:518:3 › component › blend voxels are the legend-mapped character glyphs, and billboard faces the camera (374ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:56] "GET /sample.3md HTTP/1.1" 200 - + ✓ 143 [webkit] › component.spec.mjs:537:3 › component › without a legend, blend voxels show the raw characters (263ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /sample.3md HTTP/1.1" 200 - + ✓ 144 [webkit] › component.spec.mjs:549:3 › component › blend is gated to COMPACT art: a sprawling grid is not voxelizable (falls back to deck) (267ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /sample.3md HTTP/1.1" 200 - + ✓ 145 [webkit] › component.spec.mjs:571:3 › component › map and layers keep every tile inside the stage on all edges (many tiles) (296ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /sample.3md HTTP/1.1" 200 - + ✓ 135 [webkit] › component.spec.mjs:383:3 › component › a tap (pointer, no drag) on a cross-plane link navigates (3.5s) +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /sample.3md HTTP/1.1" 200 - + ✓ 146 [webkit] › component.spec.mjs:598:3 › component › map orbit is clamped so an extreme pose never spills a tile off the stage (283ms) +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:31:57] "GET /sample.3md HTTP/1.1" 200 - + ✓ 148 [webkit] › component.spec.mjs:652:3 › component › map: no-coordinate planes lay out in a clean non-overlapping grid (267ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /sample.3md HTTP/1.1" 200 - + ✓ 147 [webkit] › component.spec.mjs:623:3 › component › map snaps coordinates to a non-overlapping grid (same x = column, same y = row) (3.6s) +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:01] "GET /sample.3md HTTP/1.1" 200 - + ✓ 149 [webkit] › component.spec.mjs:672:3 › component › map: the focused card pops to a larger readable size than the board tiles (3.5s) +[WebServer] ::1 - - [10/Oct/2026 12:32:04] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:04] "GET /sample.3md HTTP/1.1" 200 - + ✓ 150 [webkit] › component.spec.mjs:689:3 › component › map opens on a full-board overview (nothing forced open) until a tile is opened (3.6s) +[WebServer] ::1 - - [10/Oct/2026 12:32:05] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:05] "GET /sample.3md HTTP/1.1" 200 - + ✓ 151 [webkit] › component.spec.mjs:711:3 › component › map: partially-positioned planes (only x or only y) do not pile up (3.5s) +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /sample.3md HTTP/1.1" 200 - + ✓ 152 [webkit] › component.spec.mjs:728:3 › component › map: unpositioned planes do not collapse onto explicit (0,0) (3.6s) +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /embed-example.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /sample.3md HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:08] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 153 [webkit] › examples-coverage.spec.mjs:8:1 › the component renders every gallery example cleanly (6.5s) +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 154 [webkit] › lab.spec.mjs:59:3 › lab demo (index.html, backed by ) › renders via the component with no console errors (3.9s) +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:12] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 155 [webkit] › lab.spec.mjs:69:3 › lab demo (index.html, backed by ) › focused plane is frontmost across the scrubber (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 157 [webkit] › lab.spec.mjs:92:3 › lab demo (index.html, backed by ) › no horizontal overflow from 320px to 1440px (864ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:14] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 158 [webkit] › lab.spec.mjs:102:3 › lab demo (index.html, backed by ) › stepping the component highlights the synced source (984ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:14] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:14] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:15] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 156 [webkit] › lab.spec.mjs:75:3 › lab demo (index.html, backed by ) › every axis tab loads, scrubs cleanly, and syncs the source panel (4.7s) +[WebServer] ::1 - - [10/Oct/2026 12:32:17] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:17] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:17] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:17] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:17] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 159 [webkit] › robustness.spec.mjs:37:3 › robustness (no degradation under heavy use) › no rAF-loop accumulation after switching tabs many times (4.3s) +[WebServer] ::1 - - [10/Oct/2026 12:32:19] "GET /index.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:19] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 160 [webkit] › robustness.spec.mjs:65:3 › robustness (no degradation under heavy use) › DOM does not grow and the renderer stays correct after heavy use (3.9s) + ✓ 161 [webkit] › robustness.spec.mjs:95:3 › robustness (no degradation under heavy use) › rapid play/pause and scrub leave no timers or errors (2.2s) +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:21] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 162 [webkit] › snapshots.spec.mjs:37:3 › stage snapshot: stack (1.1s) + ✓ 163 [webkit] › snapshots.spec.mjs:37:3 › stage snapshot: layers (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /index.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:22] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 164 [webkit] › snapshots.spec.mjs:37:3 › stage snapshot: scene (1.0s) + ✓ 165 [webkit] › snapshots.spec.mjs:37:3 › stage snapshot: present (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 166 [webkit] › viewer.spec.mjs:34:3 › viewer & editor (viewer.html) › opening the page shows lit cubes in the window (588ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:23] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 167 [webkit] › viewer.spec.mjs:78:3 › viewer & editor (viewer.html) › one cell has filled faces from every side, with gold edges and glyph fill (806ms) + ✓ 168 [webkit] › viewer.spec.mjs:152:3 › viewer & editor (viewer.html) › clicking a visible cube picks its Z slice and blank stage does not (646ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 169 [webkit] › viewer.spec.mjs:165:3 › viewer & editor (viewer.html) › renders the starter document with no console errors (583ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:24] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 170 [webkit] › viewer.spec.mjs:176:3 › viewer & editor (viewer.html) › editing the source re-renders live (981ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 171 [webkit] › viewer.spec.mjs:190:3 › viewer & editor (viewer.html) › invalid 3md shows an error without crashing (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 172 [webkit] › viewer.spec.mjs:204:3 › viewer & editor (viewer.html) › loading an example populates the editor and viewer (1.1s) + ✓ 173 [webkit] › viewer.spec.mjs:218:3 › viewer & editor (viewer.html) › editor highlights syntax and numbers every line (703ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:26] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 174 [webkit] › viewer.spec.mjs:246:3 › viewer & editor (viewer.html) › Tab indents and Enter continues a list (671ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/tokens.css HTTP/1.1" 200 - + ✓ 175 [webkit] › viewer.spec.mjs:262:3 › viewer & editor (viewer.html) › clicking a plane outline chip focuses that plane (866ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:27] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 176 [webkit] › viewer.spec.mjs:273:3 › viewer & editor (viewer.html) › the highlight backdrop scrolls with the textarea (tall document) (670ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 177 [webkit] › viewer.spec.mjs:290:3 › viewer & editor (viewer.html) › smart-key edits are undoable and never corrupt the buffer (845ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 178 [webkit] › viewer.spec.mjs:311:3 › viewer & editor (viewer.html) › validity state is machine-readable via data attributes (898ms) + ✓ 179 [webkit] › viewer.spec.mjs:337:3 › viewer & editor (viewer.html) › Tab does not trap keyboard focus (Esc then Tab leaves the editor) (644ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:28] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 180 [webkit] › viewer.spec.mjs:351:3 › viewer & editor (viewer.html) › agent API validates and reports structured state (612ms) + ✓ 181 [webkit] › viewer.spec.mjs:364:3 › viewer & editor (viewer.html) › validate(src) is side-effect-free and reports the error code (626ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:29] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 182 [webkit] › viewer.spec.mjs:380:3 › viewer & editor (viewer.html) › repository search opens the 24-generation Conway document (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 183 [webkit] › viewer.spec.mjs:395:3 › viewer & editor (viewer.html) › kind 2 canopy opens as text in the element (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:30] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 184 [webkit] › viewer.spec.mjs:412:3 › viewer & editor (viewer.html) › linked village search resolves the folder (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:31] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 185 [webkit] › viewer.spec.mjs:426:3 › viewer & editor (viewer.html) › a composition profile shows the root and can switch entries (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:32] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 186 [webkit] › viewer.spec.mjs:441:3 › viewer & editor (viewer.html) › markdown headings become planes and a plane search opens one (1.4s) + ✓ 187 [webkit] › viewer.spec.mjs:458:3 › viewer & editor (viewer.html) › desktop layout keeps files beside a panel that switches Edit and Preview (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 189 [webkit] › viewer.spec.mjs:546:3 › viewer & editor (viewer.html) › orbiting about 1400 gpu cubes stays interactive (625ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:33] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 188 [webkit] › viewer.spec.mjs:514:3 › viewer & editor (viewer.html) › cubes tab draws a fenced grid as translucent cubes (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 190 [webkit] › viewer.spec.mjs:591:3 › viewer & editor (viewer.html) › narrow layout switches Files and the document, and Edit and Preview still switch (863ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:34] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 191 [webkit] › viewer.spec.mjs:627:3 › viewer & editor (viewer.html) › an empty document reads as a neutral prompt, not a red error (844ms) + ✓ 192 [webkit] › viewer.spec.mjs:645:3 › viewer & editor (viewer.html) › axis lint warns on a TYPO but not on a valid free-string semantic axis (495ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 193 [webkit] › viewer.spec.mjs:671:3 › viewer & editor (viewer.html) › the page has no render-mode switch and does not autoplay (489ms) + ✓ 194 [webkit] › viewer.spec.mjs:692:3 › viewer & editor (viewer.html) › the agent schema lists error codes and the axis-to-mode map (468ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:35] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 196 [webkit] › viewer.spec.mjs:713:3 › viewer & editor (viewer.html) › a corrupt share hash signals a decode error (not a silent starter) (816ms) + ✓ 195 [webkit] › viewer.spec.mjs:702:3 › viewer & editor (viewer.html) › dangling cross-plane links are flagged as a non-fatal warning (901ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 197 [webkit] › viewer.spec.mjs:722:3 › viewer & editor (viewer.html) › the embedded agent schema marks axis optional, only 3md required (466ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:36] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 198 [webkit] › viewer.spec.mjs:729:3 › viewer & editor (viewer.html) › invalid doc clears stale plane/axis data on the badge (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 199 [webkit] › viewer.spec.mjs:742:3 › viewer & editor (viewer.html) › an invalid document flags the offending line and the badge (997ms) + ✓ 200 [webkit] › viewer.spec.mjs:755:3 › viewer & editor (viewer.html) › a shared hash link restores the document (520ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 201 [webkit] › viewer.spec.mjs:766:3 › viewer & editor (viewer.html) › camera buttons and keyboard orbit, zoom, and fit without changing the document (674ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 202 [webkit] › viewer.spec.mjs:795:3 › viewer & editor (viewer.html) › full camera turns cross both poles continuously and retain geometry (718ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:38] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 203 [webkit] › viewer.spec.mjs:843:3 › viewer & editor (viewer.html) › pan tools and modified dragging move only the camera and Fit recenters (774ms) + ✓ 204 [webkit] › viewer.spec.mjs:874:3 › viewer & editor (viewer.html) › two fingers pan and pinch and a cancelled gesture cannot select a slice (585ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:39] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 206 [webkit] › viewer.spec.mjs:965:3 › viewer & editor (viewer.html) › phone layout leaves room for cubes and keeps controls outside the drawing (628ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 207 [webkit] › viewer.spec.mjs:987:3 › viewer & editor (viewer.html) › Document disclosure dismisses with Escape and both downloads preserve the document (839ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:40] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 208 [webkit] › viewer.spec.mjs:1024:3 › viewer & editor (viewer.html) › a prose document offers Preview without replacing its source (664ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:41] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 209 [webkit] › viewer.spec.mjs:1042:3 › viewer & editor (viewer.html) › slice navigation keeps the selected plane in a single scrolling row (652ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 210 [webkit] › viewer.spec.mjs:1064:3 › viewer & editor (viewer.html) › a GitHub load shows busy state and recovers after a rate limit (788ms) + ✓ 205 [webkit] › viewer.spec.mjs:897:3 › viewer & editor (viewer.html) › browser camera projects and picks the shared native parity fixture (3.9s) +[WebServer] ::1 - - [10/Oct/2026 12:32:42] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 211 [webkit] › viewer.spec.mjs:1084:3 › viewer & editor (viewer.html) › GPU unavailability explains how to keep reading in Preview (590ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:43] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 213 [webkit] › viewer.spec.mjs:1143:3 › viewer & editor (viewer.html) › composition entry switches preserve each draft without copying it into another entry (748ms) + ✓ 212 [webkit] › viewer.spec.mjs:1100:3 › viewer & editor (viewer.html) › file switches preserve edited, invalid, and empty drafts with caret and slice (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:44] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 214 [webkit] › viewer.spec.mjs:1170:3 › viewer & editor (viewer.html) › linked entries and file navigation share the same draft (823ms) + ✓ 215 [webkit] › viewer.spec.mjs:1195:3 › viewer & editor (viewer.html) › search and packing use drafts rather than original file text (821ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 216 [webkit] › viewer.spec.mjs:1212:3 › viewer & editor (viewer.html) › file filtering, keyboard selection, and phone opens reveal the document (775ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /viewer.html?src=original-document.3md&theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:45] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 217 [webkit] › viewer.spec.mjs:1240:3 › viewer & editor (viewer.html) › a failed local open preserves the collection and current draft (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 218 [webkit] › viewer.spec.mjs:1259:3 › viewer & editor (viewer.html) › explicit document navigation removes stale source queries and reloads the chosen source (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:32:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 220 [webkit] › viewer.spec.mjs:1316:3 › Sculpt Slice parity › grid edits preserve CRLF, labels, prose and downloads exactly (770ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 219 [webkit] › viewer.spec.mjs:1298:3 › Sculpt Slice parity › shared native strokes, clipped brushes, four-neighbor fill and no-op undo (2.2s) + ✓ 221 [webkit] › viewer.spec.mjs:1328:3 › Sculpt Slice parity › keyboard cells, grid zoom, previous overlay and shared WebGL reference (758ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:48] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 222 [webkit] › viewer.spec.mjs:1341:3 › Sculpt Slice parity › source typing and Slice share undo and retain it across file navigation (837ms) + ✓ 223 [webkit] › viewer.spec.mjs:1353:3 › Sculpt Slice parity › unsupported grids stay readable and budget rejection restores the full stroke (778ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:49] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 225 [webkit] › viewer.spec.mjs:1370:3 › Sculpt Slice parity › 2D editing works with an unavailable WebGL reference (671ms) + ✓ 224 [webkit] › viewer.spec.mjs:1361:3 › Sculpt Slice parity › phone Slice tools and axis controls stay usable without horizontal page overflow (970ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 226 [webkit] › viewer.spec.mjs:1375:3 › Sculpt Slice parity › axis inverse, finite inputs, pan steps and Fit leave source and geometry intact (912ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:50] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 228 [webkit] › viewer.spec.mjs:1411:1 › Slice navigation finishes a touch stroke and ignores its late pointer movement (816ms) +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:51] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 229 [webkit] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 1x density (1.9s) +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:32:53] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 230 [webkit] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 2x density (1.8s) + ✓ 227 [webkit] › viewer.spec.mjs:1389:1 › Slice history drops only old snapshots at the per-draft and collection budgets (6.5s) + + 230 passed (2.2m) diff --git a/docs/evidence/viewer-resolution/density-final.log b/docs/evidence/viewer-resolution/density-final.log new file mode 100644 index 0000000..f8b324a --- /dev/null +++ b/docs/evidence/viewer-resolution/density-final.log @@ -0,0 +1,53 @@ + +Running 4 tests using 2 workers + +(node:78296) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +(node:78295) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:32] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 1 [chromium] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 1x density (2.6s) + ✓ 2 [chromium] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 2x density (2.7s) +(node:78314) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +(node:78315) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:37:35] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 4 [webkit] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 2x density (2.0s) + ✓ 3 [webkit] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 1x density (2.3s) + + 4 passed (6.3s) diff --git a/docs/evidence/viewer-resolution/viewer-final.log b/docs/evidence/viewer-resolution/viewer-final.log new file mode 100644 index 0000000..9598ef4 --- /dev/null +++ b/docs/evidence/viewer-resolution/viewer-final.log @@ -0,0 +1,1385 @@ + +Running 130 tests using 2 workers + +(node:77726) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +(node:77727) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:08] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 2 [chromium] › viewer.spec.mjs:34:3 › viewer & editor (viewer.html) › opening the page shows lit cubes in the window (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 1 [chromium] › viewer.spec.mjs:78:3 › viewer & editor (viewer.html) › one cell has filled faces from every side, with gold edges and glyph fill (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 3 [chromium] › viewer.spec.mjs:152:3 › viewer & editor (viewer.html) › clicking a visible cube picks its Z slice and blank stage does not (773ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 4 [chromium] › viewer.spec.mjs:165:3 › viewer & editor (viewer.html) › renders the starter document with no console errors (726ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 5 [chromium] › viewer.spec.mjs:176:3 › viewer & editor (viewer.html) › editing the source re-renders live (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:10] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 6 [chromium] › viewer.spec.mjs:190:3 › viewer & editor (viewer.html) › invalid 3md shows an error without crashing (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 8 [chromium] › viewer.spec.mjs:218:3 › viewer & editor (viewer.html) › editor highlights syntax and numbers every line (731ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 7 [chromium] › viewer.spec.mjs:204:3 › viewer & editor (viewer.html) › loading an example populates the editor and viewer (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 9 [chromium] › viewer.spec.mjs:246:3 › viewer & editor (viewer.html) › Tab indents and Enter continues a list (737ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:12] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 10 [chromium] › viewer.spec.mjs:262:3 › viewer & editor (viewer.html) › clicking a plane outline chip focuses that plane (927ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 11 [chromium] › viewer.spec.mjs:273:3 › viewer & editor (viewer.html) › the highlight backdrop scrolls with the textarea (tall document) (752ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 12 [chromium] › viewer.spec.mjs:290:3 › viewer & editor (viewer.html) › smart-key edits are undoable and never corrupt the buffer (909ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 13 [chromium] › viewer.spec.mjs:311:3 › viewer & editor (viewer.html) › validity state is machine-readable via data attributes (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 14 [chromium] › viewer.spec.mjs:337:3 › viewer & editor (viewer.html) › Tab does not trap keyboard focus (Esc then Tab leaves the editor) (799ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:14] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 15 [chromium] › viewer.spec.mjs:351:3 › viewer & editor (viewer.html) › agent API validates and reports structured state (678ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 16 [chromium] › viewer.spec.mjs:364:3 › viewer & editor (viewer.html) › validate(src) is side-effect-free and reports the error code (708ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:15] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 17 [chromium] › viewer.spec.mjs:380:3 › viewer & editor (viewer.html) › repository search opens the 24-generation Conway document (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 18 [chromium] › viewer.spec.mjs:395:3 › viewer & editor (viewer.html) › kind 2 canopy opens as text in the element (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:16] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 19 [chromium] › viewer.spec.mjs:412:3 › viewer & editor (viewer.html) › linked village search resolves the folder (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:17] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 20 [chromium] › viewer.spec.mjs:426:3 › viewer & editor (viewer.html) › a composition profile shows the root and can switch entries (1.5s) +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 21 [chromium] › viewer.spec.mjs:441:3 › viewer & editor (viewer.html) › markdown headings become planes and a plane search opens one (1.4s) +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:18] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 22 [chromium] › viewer.spec.mjs:458:3 › viewer & editor (viewer.html) › desktop layout keeps files beside a panel that switches Edit and Preview (932ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 24 [chromium] › viewer.spec.mjs:546:3 › viewer & editor (viewer.html) › orbiting about 1400 gpu cubes stays interactive (821ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:19] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 23 [chromium] › viewer.spec.mjs:514:3 › viewer & editor (viewer.html) › cubes tab draws a fenced grid as translucent cubes (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 25 [chromium] › viewer.spec.mjs:591:3 › viewer & editor (viewer.html) › narrow layout switches Files and the document, and Edit and Preview still switch (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:20] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 26 [chromium] › viewer.spec.mjs:627:3 › viewer & editor (viewer.html) › an empty document reads as a neutral prompt, not a red error (960ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 27 [chromium] › viewer.spec.mjs:645:3 › viewer & editor (viewer.html) › axis lint warns on a TYPO but not on a valid free-string semantic axis (650ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 28 [chromium] › viewer.spec.mjs:671:3 › viewer & editor (viewer.html) › the page has no render-mode switch and does not autoplay (722ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:21] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 29 [chromium] › viewer.spec.mjs:692:3 › viewer & editor (viewer.html) › the agent schema lists error codes and the axis-to-mode map (759ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 30 [chromium] › viewer.spec.mjs:702:3 › viewer & editor (viewer.html) › dangling cross-plane links are flagged as a non-fatal warning (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:22] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 31 [chromium] › viewer.spec.mjs:713:3 › viewer & editor (viewer.html) › a corrupt share hash signals a decode error (not a silent starter) (938ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 32 [chromium] › viewer.spec.mjs:722:3 › viewer & editor (viewer.html) › the embedded agent schema marks axis optional, only 3md required (720ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:23] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 33 [chromium] › viewer.spec.mjs:729:3 › viewer & editor (viewer.html) › invalid doc clears stale plane/axis data on the badge (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 34 [chromium] › viewer.spec.mjs:742:3 › viewer & editor (viewer.html) › an invalid document flags the offending line and the badge (998ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 35 [chromium] › viewer.spec.mjs:755:3 › viewer & editor (viewer.html) › a shared hash link restores the document (687ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:24] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 36 [chromium] › viewer.spec.mjs:766:3 › viewer & editor (viewer.html) › camera buttons and keyboard orbit, zoom, and fit without changing the document (937ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 37 [chromium] › viewer.spec.mjs:795:3 › viewer & editor (viewer.html) › full camera turns cross both poles continuously and retain geometry (755ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:25] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 38 [chromium] › viewer.spec.mjs:843:3 › viewer & editor (viewer.html) › pan tools and modified dragging move only the camera and Fit recenters (830ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/tokens.css HTTP/1.1" 200 - + ✓ 39 [chromium] › viewer.spec.mjs:874:3 › viewer & editor (viewer.html) › two fingers pan and pinch and a cancelled gesture cannot select a slice (668ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:26] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 41 [chromium] › viewer.spec.mjs:965:3 › viewer & editor (viewer.html) › phone layout leaves room for cubes and keeps controls outside the drawing (700ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 42 [chromium] › viewer.spec.mjs:987:3 › viewer & editor (viewer.html) › Document disclosure dismisses with Escape and both downloads preserve the document (879ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:27] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 43 [chromium] › viewer.spec.mjs:1024:3 › viewer & editor (viewer.html) › a prose document offers Preview without replacing its source (815ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:28] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 44 [chromium] › viewer.spec.mjs:1042:3 › viewer & editor (viewer.html) › slice navigation keeps the selected plane in a single scrolling row (660ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 40 [chromium] › viewer.spec.mjs:897:3 › viewer & editor (viewer.html) › browser camera projects and picks the shared native parity fixture (3.5s) +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:29] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 45 [chromium] › viewer.spec.mjs:1064:3 › viewer & editor (viewer.html) › a GitHub load shows busy state and recovers after a rate limit (793ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 46 [chromium] › viewer.spec.mjs:1084:3 › viewer & editor (viewer.html) › GPU unavailability explains how to keep reading in Preview (682ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:30] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 48 [chromium] › viewer.spec.mjs:1143:3 › viewer & editor (viewer.html) › composition entry switches preserve each draft without copying it into another entry (842ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 47 [chromium] › viewer.spec.mjs:1100:3 › viewer & editor (viewer.html) › file switches preserve edited, invalid, and empty drafts with caret and slice (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:31] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 49 [chromium] › viewer.spec.mjs:1170:3 › viewer & editor (viewer.html) › linked entries and file navigation share the same draft (817ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 50 [chromium] › viewer.spec.mjs:1195:3 › viewer & editor (viewer.html) › search and packing use drafts rather than original file text (834ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:32] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 51 [chromium] › viewer.spec.mjs:1212:3 › viewer & editor (viewer.html) › file filtering, keyboard selection, and phone opens reveal the document (797ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /viewer.html?src=original-document.3md&theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 52 [chromium] › viewer.spec.mjs:1240:3 › viewer & editor (viewer.html) › a failed local open preserves the collection and current draft (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:33] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 53 [chromium] › viewer.spec.mjs:1259:3 › viewer & editor (viewer.html) › explicit document navigation removes stale source queries and reloads the chosen source (1.5s) +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:34] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 55 [chromium] › viewer.spec.mjs:1316:3 › Sculpt Slice parity › grid edits preserve CRLF, labels, prose and downloads exactly (780ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:35] "GET /viewer.html HTTP/1.1" 304 - + ✓ 56 [chromium] › viewer.spec.mjs:1328:3 › Sculpt Slice parity › keyboard cells, grid zoom, previous overlay and shared WebGL reference (885ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 54 [chromium] › viewer.spec.mjs:1298:3 › Sculpt Slice parity › shared native strokes, clipped brushes, four-neighbor fill and no-op undo (2.9s) +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:36] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 57 [chromium] › viewer.spec.mjs:1341:3 › Sculpt Slice parity › source typing and Slice share undo and retain it across file navigation (1.4s) +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:37] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 59 [chromium] › viewer.spec.mjs:1361:3 › Sculpt Slice parity › phone Slice tools and axis controls stay usable without horizontal page overflow (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /viewer.html HTTP/1.1" 200 - + ✓ 58 [chromium] › viewer.spec.mjs:1353:3 › Sculpt Slice parity › unsupported grids stay readable and budget rejection restores the full stroke (2.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:38] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 60 [chromium] › viewer.spec.mjs:1370:3 › Sculpt Slice parity › 2D editing works with an unavailable WebGL reference (716ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 61 [chromium] › viewer.spec.mjs:1375:3 › Sculpt Slice parity › axis inverse, finite inputs, pan steps and Fit leave source and geometry intact (881ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:39] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 63 [chromium] › viewer.spec.mjs:1411:1 › Slice navigation finishes a touch stroke and ignores its late pointer movement (963ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:40] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 64 [chromium] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 1x density (2.4s) +[WebServer] ::1 - - [10/Oct/2026 12:35:42] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:42] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:42] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:42] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:42] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:43] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:43] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:43] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:43] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 65 [chromium] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 2x density (2.6s) +(node:77903) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) + ✓ 62 [chromium] › viewer.spec.mjs:1389:1 › Slice history drops only old snapshots at the per-draft and collection budgets (6.7s) +(node:77913) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. +(Use `node --trace-warnings ...` to show where the warning was created) +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:46] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 66 [webkit] › viewer.spec.mjs:34:3 › viewer & editor (viewer.html) › opening the page shows lit cubes in the window (694ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 68 [webkit] › viewer.spec.mjs:152:3 › viewer & editor (viewer.html) › clicking a visible cube picks its Z slice and blank stage does not (593ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 67 [webkit] › viewer.spec.mjs:78:3 › viewer & editor (viewer.html) › one cell has filled faces from every side, with gold edges and glyph fill (1.1s) + ✓ 69 [webkit] › viewer.spec.mjs:165:3 › viewer & editor (viewer.html) › renders the starter document with no console errors (457ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:47] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:48] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 71 [webkit] › viewer.spec.mjs:190:3 › viewer & editor (viewer.html) › invalid 3md shows an error without crashing (938ms) + ✓ 70 [webkit] › viewer.spec.mjs:176:3 › viewer & editor (viewer.html) › editing the source re-renders live (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 73 [webkit] › viewer.spec.mjs:218:3 › viewer & editor (viewer.html) › editor highlights syntax and numbers every line (718ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:49] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 72 [webkit] › viewer.spec.mjs:204:3 › viewer & editor (viewer.html) › loading an example populates the editor and viewer (1.1s) + ✓ 74 [webkit] › viewer.spec.mjs:246:3 › viewer & editor (viewer.html) › Tab indents and Enter continues a list (592ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 75 [webkit] › viewer.spec.mjs:262:3 › viewer & editor (viewer.html) › clicking a plane outline chip focuses that plane (848ms) + ✓ 76 [webkit] › viewer.spec.mjs:273:3 › viewer & editor (viewer.html) › the highlight backdrop scrolls with the textarea (tall document) (746ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:50] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 77 [webkit] › viewer.spec.mjs:290:3 › viewer & editor (viewer.html) › smart-key edits are undoable and never corrupt the buffer (832ms) + ✓ 78 [webkit] › viewer.spec.mjs:311:3 › viewer & editor (viewer.html) › validity state is machine-readable via data attributes (921ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:51] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 80 [webkit] › viewer.spec.mjs:351:3 › viewer & editor (viewer.html) › agent API validates and reports structured state (559ms) + ✓ 79 [webkit] › viewer.spec.mjs:337:3 › viewer & editor (viewer.html) › Tab does not trap keyboard focus (Esc then Tab leaves the editor) (765ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:52] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 81 [webkit] › viewer.spec.mjs:364:3 › viewer & editor (viewer.html) › validate(src) is side-effect-free and reports the error code (574ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 82 [webkit] › viewer.spec.mjs:380:3 › viewer & editor (viewer.html) › repository search opens the 24-generation Conway document (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:53] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 83 [webkit] › viewer.spec.mjs:395:3 › viewer & editor (viewer.html) › kind 2 canopy opens as text in the element (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 84 [webkit] › viewer.spec.mjs:412:3 › viewer & editor (viewer.html) › linked village search resolves the folder (1.0s) +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:54] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 85 [webkit] › viewer.spec.mjs:426:3 › viewer & editor (viewer.html) › a composition profile shows the root and can switch entries (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:55] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 86 [webkit] › viewer.spec.mjs:441:3 › viewer & editor (viewer.html) › markdown headings become planes and a plane search opens one (1.4s) +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 87 [webkit] › viewer.spec.mjs:458:3 › viewer & editor (viewer.html) › desktop layout keeps files beside a panel that switches Edit and Preview (847ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:56] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 89 [webkit] › viewer.spec.mjs:546:3 › viewer & editor (viewer.html) › orbiting about 1400 gpu cubes stays interactive (644ms) + ✓ 88 [webkit] › viewer.spec.mjs:514:3 › viewer & editor (viewer.html) › cubes tab draws a fenced grid as translucent cubes (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 90 [webkit] › viewer.spec.mjs:591:3 › viewer & editor (viewer.html) › narrow layout switches Files and the document, and Edit and Preview still switch (809ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:57] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 91 [webkit] › viewer.spec.mjs:627:3 › viewer & editor (viewer.html) › an empty document reads as a neutral prompt, not a red error (947ms) + ✓ 92 [webkit] › viewer.spec.mjs:645:3 › viewer & editor (viewer.html) › axis lint warns on a TYPO but not on a valid free-string semantic axis (493ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 93 [webkit] › viewer.spec.mjs:671:3 › viewer & editor (viewer.html) › the page has no render-mode switch and does not autoplay (522ms) + ✓ 94 [webkit] › viewer.spec.mjs:692:3 › viewer & editor (viewer.html) › the agent schema lists error codes and the axis-to-mode map (536ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:58] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 95 [webkit] › viewer.spec.mjs:702:3 › viewer & editor (viewer.html) › dangling cross-plane links are flagged as a non-fatal warning (941ms) + ✓ 96 [webkit] › viewer.spec.mjs:713:3 › viewer & editor (viewer.html) › a corrupt share hash signals a decode error (not a silent starter) (795ms) +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:35:59] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 97 [webkit] › viewer.spec.mjs:722:3 › viewer & editor (viewer.html) › the embedded agent schema marks axis optional, only 3md required (418ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 98 [webkit] › viewer.spec.mjs:729:3 › viewer & editor (viewer.html) › invalid doc clears stale plane/axis data on the badge (837ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:00] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 99 [webkit] › viewer.spec.mjs:742:3 › viewer & editor (viewer.html) › an invalid document flags the offending line and the badge (954ms) + ✓ 100 [webkit] › viewer.spec.mjs:755:3 › viewer & editor (viewer.html) › a shared hash link restores the document (517ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 102 [webkit] › viewer.spec.mjs:795:3 › viewer & editor (viewer.html) › full camera turns cross both poles continuously and retain geometry (660ms) + ✓ 101 [webkit] › viewer.spec.mjs:766:3 › viewer & editor (viewer.html) › camera buttons and keyboard orbit, zoom, and fit without changing the document (793ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:01] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 103 [webkit] › viewer.spec.mjs:843:3 › viewer & editor (viewer.html) › pan tools and modified dragging move only the camera and Fit recenters (684ms) + ✓ 104 [webkit] › viewer.spec.mjs:874:3 › viewer & editor (viewer.html) › two fingers pan and pinch and a cancelled gesture cannot select a slice (642ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:02] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 106 [webkit] › viewer.spec.mjs:965:3 › viewer & editor (viewer.html) › phone layout leaves room for cubes and keeps controls outside the drawing (699ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:03] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 107 [webkit] › viewer.spec.mjs:987:3 › viewer & editor (viewer.html) › Document disclosure dismisses with Escape and both downloads preserve the document (807ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 108 [webkit] › viewer.spec.mjs:1024:3 › viewer & editor (viewer.html) › a prose document offers Preview without replacing its source (669ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:04] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 109 [webkit] › viewer.spec.mjs:1042:3 › viewer & editor (viewer.html) › slice navigation keeps the selected plane in a single scrolling row (607ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 110 [webkit] › viewer.spec.mjs:1064:3 › viewer & editor (viewer.html) › a GitHub load shows busy state and recovers after a rate limit (655ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:05] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 105 [webkit] › viewer.spec.mjs:897:3 › viewer & editor (viewer.html) › browser camera projects and picks the shared native parity fixture (4.1s) + ✓ 111 [webkit] › viewer.spec.mjs:1084:3 › viewer & editor (viewer.html) › GPU unavailability explains how to keep reading in Preview (585ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:06] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 113 [webkit] › viewer.spec.mjs:1143:3 › viewer & editor (viewer.html) › composition entry switches preserve each draft without copying it into another entry (773ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - + ✓ 112 [webkit] › viewer.spec.mjs:1100:3 › viewer & editor (viewer.html) › file switches preserve edited, invalid, and empty drafts with caret and slice (1.1s) +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:07] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 114 [webkit] › viewer.spec.mjs:1170:3 › viewer & editor (viewer.html) › linked entries and file navigation share the same draft (756ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 115 [webkit] › viewer.spec.mjs:1195:3 › viewer & editor (viewer.html) › search and packing use drafts rather than original file text (828ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:08] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 116 [webkit] › viewer.spec.mjs:1212:3 › viewer & editor (viewer.html) › file filtering, keyboard selection, and phone opens reveal the document (901ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /viewer.html?src=original-document.3md&theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 117 [webkit] › viewer.spec.mjs:1240:3 › viewer & editor (viewer.html) › a failed local open preserves the collection and current draft (1.2s) +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /viewer.html?theme=dark HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:09] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 118 [webkit] › viewer.spec.mjs:1259:3 › viewer & editor (viewer.html) › explicit document navigation removes stale source queries and reloads the chosen source (1.3s) +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 120 [webkit] › viewer.spec.mjs:1316:3 › Sculpt Slice parity › grid edits preserve CRLF, labels, prose and downloads exactly (761ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:10] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 121 [webkit] › viewer.spec.mjs:1328:3 › Sculpt Slice parity › keyboard cells, grid zoom, previous overlay and shared WebGL reference (815ms) + ✓ 119 [webkit] › viewer.spec.mjs:1298:3 › Sculpt Slice parity › shared native strokes, clipped brushes, four-neighbor fill and no-op undo (2.3s) +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:11] "GET /nested-examples.json HTTP/1.1" 200 - + ✓ 122 [webkit] › viewer.spec.mjs:1341:3 › Sculpt Slice parity › source typing and Slice share undo and retain it across file navigation (833ms) + ✓ 123 [webkit] › viewer.spec.mjs:1353:3 › Sculpt Slice parity › unsupported grids stay readable and budget rejection restores the full stroke (848ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:12] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 125 [webkit] › viewer.spec.mjs:1370:3 › Sculpt Slice parity › 2D editing works with an unavailable WebGL reference (696ms) + ✓ 124 [webkit] › viewer.spec.mjs:1361:3 › Sculpt Slice parity › phone Slice tools and axis controls stay usable without horizontal page overflow (830ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:13] "GET /gallery-data.json HTTP/1.1" 200 - + ✓ 126 [webkit] › viewer.spec.mjs:1375:3 › Sculpt Slice parity › axis inverse, finite inputs, pan steps and Fit leave source and geometry intact (896ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:14] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 128 [webkit] › viewer.spec.mjs:1411:1 › Slice navigation finishes a touch stroke and ignores its late pointer movement (725ms) +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /all-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:15] "GET /binary-samples.json HTTP/1.1" 200 - + ✓ 129 [webkit] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 1x density (1.8s) +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /viewer.html HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /assets/tokens.css HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /assets/theme.js HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /assets/three-md.js?v=1.7.17 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /assets/open-document.js?v=3 HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /nested-examples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /binary-samples.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /gallery-data.json HTTP/1.1" 200 - +[WebServer] ::1 - - [10/Oct/2026 12:36:16] "GET /all-examples.json HTTP/1.1" 200 - + ✓ 130 [webkit] › viewer.spec.mjs:1427:3 › shared cube drawable stays sharp through view/viewport changes at 2x density (1.9s) + ✓ 127 [webkit] › viewer.spec.mjs:1389:1 › Slice history drops only old snapshots at the per-draft and collection budgets (6.8s) + + 130 passed (1.2m) diff --git a/specs/ThreeMDViewer/ThreeMDViewer.spec.md b/specs/ThreeMDViewer/ThreeMDViewer.spec.md index e44f172..7c1e114 100644 --- a/specs/ThreeMDViewer/ThreeMDViewer.spec.md +++ b/specs/ThreeMDViewer/ThreeMDViewer.spec.md @@ -1,6 +1,6 @@ --- module: ThreeMDViewer -version: 16 +version: 17 status: active files: - web/viewer.html @@ -156,14 +156,13 @@ Acceptance Criteria: | 2026-10-10 | ThreeMDViewer change | Draw every cube face. Each cell is a solid cube. | | 2026-10-09 | agent:codex | Match Sculpt fill, glyph edges, gold selected-slice edges, background, document axes, and camera framing; retain one instanced draw and geometry reuse. | | 2026-10-09 | agent:codex | Compact the workspace, group document actions, add Fit and accessible camera/slice controls, and clarify empty and loading states under Leif’s request to continue improving UI and UX. The layout definition remains an unapproved draft. | - | 2026-10-10 | agent:codex | Preserve file and composition drafts across navigation, expose edited state, and improve file filtering, keyboard navigation, mobile reveal, and current-document URLs in a follow-up PR after PR 92 merged. The definition remains an unapproved draft. | - | 2026-10-10 | agent:codex | Preserve the slice across editor refresh, sort file paths for consistent keyboard navigation, and compact small-phone spacing. Leif approved the final scope; verification, acceptance, and archiving are pending. | | 2026-10-10 | SpecSync | put-edit-and-preview-in-the-same-viewer-panel-and-toggle-them-like-github-files-stay-on-the-left-edit-shows-first-below: Put Edit and Preview in the same viewer panel and toggle them like GitHub. Files stay on the left. Edit shows first. Below 900px, Files and the document take turns, and the document panel still switches Edit and Preview. | | 2026-10-10 | SpecSync | keep-sculpt-and-web-cube-cameras-in-parity-with-unrestricted-orbit-and-screen-space-pan: Keep Sculpt and web cube cameras in parity with unrestricted orbit and screen-space pan | | 2026-10-10 | SpecSync | bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference: Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference | | 2026-10-10 | SpecSync | add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer: Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer | +| 2026-10-10 | agent:codex | Repair the frozen small drawable being stretched across Cubes after Slice or phone layout; update only changed bitmap dimensions and retain the context, geometry and camera. | ## Slice and precise camera parity diff --git a/specs/ThreeMDViewer/context.md b/specs/ThreeMDViewer/context.md index 5ceac87..5f35cef 100644 --- a/specs/ThreeMDViewer/context.md +++ b/specs/ThreeMDViewer/context.md @@ -38,7 +38,7 @@ spec: ThreeMDViewer.spec.md - Sculpt was run locally and its Character orb compared in both live stages. Native and web screenshots are in `docs/evidence/viewer-sculpt-parity/`. This is agent visual verification, not Leif’s review or definition approval. - Leif directly requested continued UI and UX work on 2026-10-09. This covers the compact workspace and controls in the existing page scope; it does not record definition approval, human diff review, or a merge. -- The canvas occupies the space above the camera strip. Framing and picking use its actual client dimensions; changing view or viewport still does not resize an established WebGL bitmap. +- The canvas occupies the space above the camera strip. Framing and picking use its actual client dimensions; changing view or viewport updates the drawable to the displayed pane and capped device pixel ratio while retaining the established WebGL context and geometry. - Export and conversion actions use a native disclosure with natural button focus, Escape dismissal, and outside-click closure. The source download shortcut preserves editor focus. - PR 92 has merged. Leif requested a new fix PR for file navigation. Draft state belongs to the page and survives file and composition-entry switches within the current collection. It is not browser storage or a write to the source files. That follow-up was kept in draft until Leif's explicit 2026-10-10 scope approval. @@ -58,3 +58,7 @@ Slice uses the native character palette `#@*+ox:=-`, Draw/Erase square brushes 1 History is shared with source typing and attached to each draft state, including linked entries. It retains at most 100 snapshots per draft and 8 MiB across the current collection; no-op strokes add no entry. Pointer up, cancellation, lost capture and navigation finish the accepted transaction. Thumbnails, one-based coordinates, keyboard arrows/Space, explicit cell Apply, previous-slice ghosts and Fit/2x/4x/8x/16x grid zoom use the same state. The live reference reparents the existing WebGL canvas rather than allocating another context; 2D editing remains available without WebGL. Phone layouts scroll inside Slice with full-size touch targets. The volume camera shows colored X/Y/Z rings and Free/X/Y/Z constraints. A normalized quaternion composes document-axis rotation with continuous free orbit. Numerical rotation defaults to 15 degrees and pan to 0.25 cells, accepting only finite positive steps. Fit restores the default orientation and zero pan. Shared independent matrix-reference cases cover three-axis projection and picking; shared edit cases run through actual Sculpt workspaces and browser pointer gestures. + +## Shared 3D drawable resolution repair + +The previous frozen bitmap could initialize at 368x322 in a small view and stretch to 1099x911 after expansion. Drawable dimensions now follow the visible pane at up to 2x pixel density with the existing proportional 2048-edge cap. Only changed dimensions are assigned; context, GPU resources, pose and source remain installed. Chromium/WebKit density 1/2 regressions exercise phone, reference, full stage and capped large sizes. diff --git a/specs/ThreeMDViewer/testing.md b/specs/ThreeMDViewer/testing.md index c2b8a09..3bc142c 100644 --- a/specs/ThreeMDViewer/testing.md +++ b/specs/ThreeMDViewer/testing.md @@ -70,3 +70,9 @@ The volume camera shows colored X/Y/Z rings and Free/X/Y/Z constraints. A normal 2026-10-10: complete macOS UI 226 passed without skips or retries; Linux CI UI 218 passed with 8 existing platform-snapshot skips and no retries; configured native suite 637 passed and final parity selection 11 passed. Shared fixtures compare native workspace edits and actual browser gestures against independent expected rows and camera matrices. Logs and actual UI screenshots are in `docs/evidence/viewer-slice/`. Pinned Trust passed for implementation commit `8e9a0c4`; final archive-tip verification remains separate. Actual unsigned agent:codex provenance is recorded and does not satisfy the unchanged strict permitted-signature/reviewer policy. Both current approved changes were successfully finalized and archived on 2026-10-10. Their supported scoped review records identify agent:codex. Scope authorization and agent verification do not claim independent human review or a permitted signature. Exact final archive-head Trust and remote CI status are reported in PR #93; the implementation and test fixtures are unchanged from `8e9a0c4`. + +## Drawable resolution regression + +At 1x and 2x density, exercise a phone-initialized canvas, small Slice reference, expanded Cubes stage and larger-than-cap desktop. Assert actual WebGL drawing-buffer dimensions match proportional 2048-edge/2x bounds, with one context, no context-loss events, no geometry allocations/uploads and unchanged pose/source/selection. Existing pixel/projection/nearest-picking checks continue on both engines. + +2026-10-10: the post-resize full UI suite passed 230 tests; the final viewer suite including display-density listeners passed 130 tests; the final media-query/window-resize regressions passed 4 tests. No skips or retries. Actual browser bitmap/display measurements, screenshots, logs and implementation digests are in `docs/evidence/viewer-resolution/`; repository Trust and lifecycle verification remain separate. Native source is unchanged. diff --git a/uitests/viewer.spec.mjs b/uitests/viewer.spec.mjs index c07c62e..0510d4a 100644 --- a/uitests/viewer.spec.mjs +++ b/uitests/viewer.spec.mjs @@ -1421,3 +1421,84 @@ test("Slice navigation finishes a touch stroke and ignores its late pointer move await openedFile(page,"one.3md").click();expect(await page.evaluate(()=>window.threeMd.source)).toBe(source.replace('...\n...','#..\n...')); await page.locator("#sliceUndo").click();expect(await page.evaluate(()=>window.threeMd.source)).toBe(source); }); + + +for (const density of [1, 2]) { + test(`shared cube drawable stays sharp through view/viewport changes at ${density}x density`, async ({ browser }) => { + const context = await browser.newContext({ viewport: { width: 390, height: 844 }, deviceScaleFactor: density }); + try { + const page = await context.newPage(); + await page.addInitScript(() => { + window.__cubeResolution = { contexts: 0, losses: 0, uploads: 0, allocations: 0 }; + const original = HTMLCanvasElement.prototype.getContext; + HTMLCanvasElement.prototype.getContext = function(type, ...args) { + if (this.id === "cubeCanvas" && type === "webgl2") window.__cubeResolution.contexts++; + return original.call(this, type, ...args); + }; + document.addEventListener("webglcontextlost", () => window.__cubeResolution.losses++, true); + const media = window.matchMedia.bind(window); + window.matchMedia = query => { + const result = media(query); + if (query.startsWith("(resolution:")) window.__cubeResolution.display = result; + return result; + }; + }); + await page.goto("/viewer.html"); await viewerReady(page); + await page.waitForFunction(() => document.getElementById("cubeCanvas").dataset.renderer === "webgl2"); + await page.locator("#outline button").nth(1).click(); + await page.locator('#axisButtons [data-axis="2"]').click(); + await page.locator("#cubeCanvas").press("ArrowRight"); + const source = await page.evaluate(() => window.threeMd.source); + const pose = await page.evaluate(() => { + const canvas = document.getElementById("cubeCanvas"), gl = canvas.__cubeGl; + window.__cubeResolution.gl = gl; + window.__cubeResolution.program = gl.getParameter(gl.CURRENT_PROGRAM); + const upload = gl.bufferSubData.bind(gl), allocate = gl.bufferData.bind(gl); + gl.bufferSubData = (...args) => { window.__cubeResolution.uploads++; return upload(...args); }; + gl.bufferData = (...args) => { window.__cubeResolution.allocations++; return allocate(...args); }; + return [canvas.dataset.rotation, canvas.dataset.yaw, canvas.dataset.pitch, canvas.dataset.panX, canvas.dataset.panY]; + }); + const sharp = async () => { + await expect.poll(() => page.evaluate(() => { + const canvas = document.getElementById("cubeCanvas"), gl = canvas.__cubeGl; + let w = Math.max(2, Math.floor(canvas.clientWidth * Math.min(devicePixelRatio, 2))); + let h = Math.max(2, Math.floor(canvas.clientHeight * Math.min(devicePixelRatio, 2))); + const limit = Math.min(1, 2048 / w, 2048 / h); + w = Math.max(2, Math.floor(w * limit)); h = Math.max(2, Math.floor(h * limit)); + return canvas.width === w && canvas.height === h && gl?.drawingBufferWidth === w && gl?.drawingBufferHeight === h; + })).toBe(true); + const state = await page.evaluate(() => { + const canvas = document.getElementById("cubeCanvas"), gl = canvas.__cubeGl, receipt = window.__cubeResolution; + return { sameContext: gl === receipt.gl, sameProgram: gl?.getParameter(gl.CURRENT_PROGRAM) === receipt.program, + contexts: receipt.contexts, losses: receipt.losses, uploads: receipt.uploads, allocations: receipt.allocations, + pose: [canvas.dataset.rotation, canvas.dataset.yaw, canvas.dataset.pitch, canvas.dataset.panX, canvas.dataset.panY] }; + }); + expect(state).toEqual({ sameContext: true, sameProgram: true, contexts: 1, losses: 0, uploads: 0, allocations: 0, pose }); + expect(await page.evaluate(() => window.threeMd.source)).toBe(source); + await expect(page.locator("#planeLive")).toHaveText("Plane 2 of 3: walls"); + }; + await sharp(); + for (const viewport of [{ width: 1440, height: 1000 }, { width: 3200, height: 2000 }, { width: 390, height: 844 }]) { + await page.locator("#sliceTab").click(); await sharp(); + await page.setViewportSize(viewport); await sharp(); + await page.locator("#sliceExpand").click(); await sharp(); + } + for (let i = 0; i < 3; i++) { + await page.locator("#sliceTab").click(); await sharp(); + await page.locator("#cubesTab").click(); await sharp(); + } + // A display-density change can leave the CSS size unchanged. + await page.evaluate(value => { + Object.defineProperty(window, "devicePixelRatio", { configurable: true, value }); + window.__cubeResolution.display.dispatchEvent(new Event("change")); + }, density === 1 ? 2 : 1); + await sharp(); + expect(await page.evaluate(() => window.__cubeResolution.display.media)).toBe(`(resolution: ${density === 1 ? 2 : 1}dppx)`); + await page.evaluate(value => { + Object.defineProperty(window, "devicePixelRatio", { configurable: true, value }); + window.dispatchEvent(new Event("resize")); + }, density); + await sharp(); + } finally { await context.close(); } + }); +} diff --git a/web/viewer.html b/web/viewer.html index 35d6e16..eb69d9a 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -1901,8 +1901,8 @@

3md viewer.

} function initCubeGl(canvas) { if (cubeGpu.failed) return false; - // One context, created after the bitmap size is final. Resizing the bitmap - // or asking for the discrete GPU makes Safari drop the context. + // Keep one context and its installed resources. Drawable resizing is handled + // separately; avoid forcing a discrete GPU on Safari. const gl = canvas.getContext("webgl2", { alpha: false, antialias: true, @@ -2155,12 +2155,11 @@

3md viewer.

if (width < 2 || height < 2) return; bindCubeContext(canvas); const [bufferWidth, bufferHeight] = cubeBufferSize(width, height); - // Set the bitmap before the first getContext. Changing it later drops the - // Safari context, so a later layout change only updates the viewport. - if (!cubeGpu.gl) { - canvas.width = bufferWidth; - canvas.height = bufferHeight; - } + // A small Slice reference must not leave a low-resolution bitmap stretched + // across Cubes. Resize only changed drawable dimensions; keep the context, + // program and geometry installed, then redraw with the current camera. + if (canvas.width !== bufferWidth) canvas.width = bufferWidth; + if (canvas.height !== bufferHeight) canvas.height = bufferHeight; if (cubeGpu.gl && cubeGpu.gl.isContextLost()) { cubeGpu.gl = null; canvas.dataset.renderer = "lost"; @@ -2754,6 +2753,15 @@

3md viewer.

if (["cubes", "slice"].includes(stage.dataset.show)) drawCubes(); }).observe(cubeCanvas); } + const redrawForDisplay = () => { + if (["cubes", "slice"].includes(stage.dataset.show)) requestAnimationFrame(drawCubes); + }; + window.addEventListener("resize", redrawForDisplay); + function watchPixelDensity() { + const display = matchMedia(`(resolution: ${window.devicePixelRatio || 1}dppx)`); + display.addEventListener("change", () => { watchPixelDensity(); redrawForDisplay(); }, { once: true }); + } + watchPixelDensity(); document.getElementById("cubeSample").addEventListener("click", () => { showOpened(openText(STARTER)); documentURL(); From cc71e781a3226550611ea09d8637cbaf2e67a1c8 Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:45:19 -0600 Subject: [PATCH 40/43] Record verified drawable repair and actual provenance --- .../tasks.md | 2 +- .../testing.md | 6 + docs/evidence/viewer-resolution/README.md | 6 + .../attest-implementation.json | 1 + .../viewer-resolution/attest-policy.json | 1 + .../strict-implementation.json | 11 + .../trust-implementation.log | 1489 +++++++++++++++++ specs/ThreeMDViewer/testing.md | 2 + 8 files changed, 1517 insertions(+), 1 deletion(-) create mode 100644 docs/evidence/viewer-resolution/attest-implementation.json create mode 100644 docs/evidence/viewer-resolution/attest-policy.json create mode 100644 docs/evidence/viewer-resolution/strict-implementation.json create mode 100644 docs/evidence/viewer-resolution/trust-implementation.log diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md index 1c413ed..9587a86 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md @@ -10,4 +10,4 @@ artifact: tasks - [x] Make the shared 3D drawable follow visible pane and display density. - [x] Verify Chromium/WebKit small-to-large, Slice/Cubes, desktop/phone and Retina transitions with one retained context and no geometry uploads. - [x] Inspect sharp output in the actual in-app browser without losing Leif's edited draft. -- [ ] Synchronize implementation notes, run strict specs and pinned Trust, and record actual provenance. +- [x] Synchronize implementation notes, run strict specs and pinned Trust, and record actual provenance. diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md index dfba0cb..2e23941 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md @@ -16,3 +16,9 @@ At device pixel ratios 1 and 2, initialize a phone-sized Cubes stage, switch thr ## Current results The complete post-resize UI suite passed 230 tests. After final display-density listeners, the viewer suite passed 130 tests. The final media-query/window-resize density regressions passed 4 tests. All ran on Chromium and WebKit without skips or retries. Actual in-app bitmap/display measurements and screenshots, test logs and implementation digests are in `docs/evidence/viewer-resolution/`. Pinned Trust, actual provenance and finalization remain separately evidenced. + +## Repository verification and provenance + +Pinned Trust 1.2.2 with Fledge 1.7.2 passed on implementation commit `95c1213886b853a7b945fd833a5af02fa0f8128d`; Augur returned review at risk 36, with configured soft provenance degradation. The full configured verification lane passed. Strict root specs passed at 55/55 files and Hi passed 87 criteria. Source digests above bind the browser results to this implementation; later lifecycle/materialization records do not change the HTML or tests. + +Actual unsigned agent:codex attestation was recorded after the lane passed. The unchanged strict Attest policy rejects the unavailable permitted signature and reviewer allow-list, as shown in `attest-policy.json`. This is not a human review or signed provenance claim, and no policy was changed. Lifecycle closure is recorded separately in its supported receipt. diff --git a/docs/evidence/viewer-resolution/README.md b/docs/evidence/viewer-resolution/README.md index aad18cc..deb66df 100644 --- a/docs/evidence/viewer-resolution/README.md +++ b/docs/evidence/viewer-resolution/README.md @@ -18,3 +18,9 @@ Native behavior was already verified in `../viewer-slice/`; it is unchanged by t - `web/viewer.html`: `d5c226e7ccb6b46c7e462c6d72a89772138080dce9269f0813cd0979d10116b8` - `uitests/viewer.spec.mjs`: `59894ffd439caff704f34d3fba39425e991f854fcfe83a73aca673b0883c1c97` + +## Repository verification and provenance + +Pinned Trust 1.2.2 with Fledge 1.7.2 passed on implementation commit `95c1213886b853a7b945fd833a5af02fa0f8128d`; Augur returned review at risk 36, with configured soft provenance degradation. The full configured verification lane passed. Strict root specs passed at 55/55 files and Hi passed 87 criteria. Source digests above bind the browser results to this implementation; later lifecycle/materialization records do not change the HTML or tests. + +Actual unsigned agent:codex attestation was recorded after the lane passed. The unchanged strict Attest policy rejects the unavailable permitted signature and reviewer allow-list, as shown in `attest-policy.json`. This is not a human review or signed provenance claim, and no policy was changed. Lifecycle closure is recorded separately in its supported receipt. diff --git a/docs/evidence/viewer-resolution/attest-implementation.json b/docs/evidence/viewer-resolution/attest-implementation.json new file mode 100644 index 0000000..519ef9c --- /dev/null +++ b/docs/evidence/viewer-resolution/attest-implementation.json @@ -0,0 +1 @@ +{"commit":"95c1213886b853a7b945fd833a5af02fa0f8128d","confidence":0.86,"humanApproved":false,"note":"Blur repair verified: post-resize full UI 230 passed; final viewer with density listeners 130 passed; final density media-query and resize cases 4 passed; strict specs and Hi passed; pinned Trust passed at 95c1213 with Augur review risk 36 and soft provenance degradation. Actual in-app measurements and images verify matching bitmap/display dimensions. This is unsigned Codex agent verification, not Leif diff review, independent human approval or a permitted signature.","reviewer":"agent:codex","testsPassed":true,"timestamp":1791657883,"verdict":"review"} diff --git a/docs/evidence/viewer-resolution/attest-policy.json b/docs/evidence/viewer-resolution/attest-policy.json new file mode 100644 index 0000000..341fdda --- /dev/null +++ b/docs/evidence/viewer-resolution/attest-policy.json @@ -0,0 +1 @@ +{"checkedCommits":1,"passed":false,"violations":[{"commit":"95c1213886b853a7b945fd833a5af02fa0f8128d","detail":"no valid signed attestation","rule":"requireSignature"},{"commit":"95c1213886b853a7b945fd833a5af02fa0f8128d","detail":"reviewer agent:codex is not in the allow-list [\"agent:claude\", \"human:\"]","rule":"allowedReviewers"}]} diff --git a/docs/evidence/viewer-resolution/strict-implementation.json b/docs/evidence/viewer-resolution/strict-implementation.json new file mode 100644 index 0000000..1752338 --- /dev/null +++ b/docs/evidence/viewer-resolution/strict-implementation.json @@ -0,0 +1,11 @@ +{ + "errors": [], + "manifest_notices": [], + "notices": [], + "passed": true, + "skipped_links": [], + "specs_checked": 4, + "stale": [], + "suppressed_warnings": [], + "warnings": [] +} diff --git a/docs/evidence/viewer-resolution/trust-implementation.log b/docs/evidence/viewer-resolution/trust-implementation.log new file mode 100644 index 0000000..08a1cb4 --- /dev/null +++ b/docs/evidence/viewer-resolution/trust-implementation.log @@ -0,0 +1,1489 @@ +▶️ Lane: verify — Three language suites, nine-pair public-package interchange, generated bundle drift and editor grammar. Trust runs SpecSync after this lane. + ▶️ Running task: lint + ✔ Step 1 done (597ms) + ▶️ Running task: build +Building for debugging... +[0/5] Write swift-version--58304C5D6DBC2206.txt +Build complete! (0.13s) + ✔ Step 2 done (641ms) + ▶️ Running task: test +[0/1] Planning build +Building for debugging... +[0/6] Write swift-version--58304C5D6DBC2206.txt +Build complete! (0.20s) +Test Suite 'All tests' started at 2026-10-10 12:40:49.862. +Test Suite '3mdPackageTests.xctest' started at 2026-10-10 12:40:49.863. +Test Suite 'CompositionEditingTests' started at 2026-10-10 12:40:49.863. +Test Case '-[ThreeMDTests.CompositionEditingTests testCancelledGraphTransactionPropagatesCancellation]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testCancelledGraphTransactionPropagatesCancellation]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testEntryReplacementKeepsIDAndCanEditSharedDefinitionWithoutFlattening]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testEntryReplacementKeepsIDAndCanEditSharedDefinitionWithoutFlattening]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testFinalGraphValidationAllowsForwardReferenceInsertionAndRootReplacement]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testFinalGraphValidationAllowsForwardReferenceInsertionAndRootReplacement]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphRevisionIncludesReferenceOrderAttributesAndRootAndSurvivesReopen]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphRevisionIncludesReferenceOrderAttributesAndRootAndSurvivesReopen]' passed (0.008 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphSnapshotsAndPatchesAreCodableAndDecodedGraphsStillValidate]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphSnapshotsAndPatchesAreCodableAndDecodedGraphsStillValidate]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphTransactionBoundsOperationsPayloadAndDefinitions]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testGraphTransactionBoundsOperationsPayloadAndDefinitions]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testMissingTargetAndCycleFailuresHaveGraphPathsWithoutPartialPublication]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testMissingTargetAndCycleFailuresHaveGraphPathsWithoutPartialPublication]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceIdentityCannotChangeOrBeDuplicatedWithinOwner]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceIdentityCannotChangeOrBeDuplicatedWithinOwner]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceRetargetMoveAndRemoveKeepInstanceIdentityAndOpaqueAttributes]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testReferenceRetargetMoveAndRemoveKeepInstanceIdentityAndOpaqueAttributes]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.CompositionEditingTests testRemovingAndRewritingReferencesValidatesOnlyCompleteFinalGraph]' started. +Test Case '-[ThreeMDTests.CompositionEditingTests testRemovingAndRewritingReferencesValidatesOnlyCompleteFinalGraph]' passed (0.002 seconds). +Test Suite 'CompositionEditingTests' passed at 2026-10-10 12:40:49.899. + Executed 10 tests, with 0 failures (0 unexpected) in 0.035 (0.037) seconds +Test Suite 'ConformanceTests' started at 2026-10-10 12:40:49.899. +Test Case '-[ThreeMDTests.ConformanceTests testConformanceVectors]' started. +Test Case '-[ThreeMDTests.ConformanceTests testConformanceVectors]' passed (0.010 seconds). +Test Suite 'ConformanceTests' passed at 2026-10-10 12:40:49.909. + Executed 1 test, with 0 failures (0 unexpected) in 0.010 (0.010) seconds +Test Suite 'CrossPlaneLinkHTMLTests' started at 2026-10-10 12:40:49.909. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testAnchorHrefMatchesSectionId]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testAnchorHrefMatchesSectionId]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDecimalTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDecimalTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDefaultTextIsEscaped]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorDefaultTextIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorEmptyText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorEmptyText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNegativeTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNegativeTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNoText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorNoText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorScientificNotation]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorScientificNotation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorTextIsEscaped]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorTextIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorWithText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testCrossPlaneAnchorWithText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testHexTargetNotRenderedAsAnchor]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testHexTargetNotRenderedAsAnchor]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInfTargetNotRenderedAsAnchor]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInfTargetNotRenderedAsAnchor]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInvalidTargetNotRenderedAsAnchor]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testInvalidTargetNotRenderedAsAnchor]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testPublicAnchorHelpersMatchRendererIds]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testPublicAnchorHelpersMatchRendererIds]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionHasIdAttribute]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionHasIdAttribute]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForDecimalZ]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForDecimalZ]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForNegativeZ]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdForNegativeZ]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdPrecedesDataZ]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkHTMLTests testSectionIdPrecedesDataZ]' passed (0.000 seconds). +Test Suite 'CrossPlaneLinkHTMLTests' passed at 2026-10-10 12:40:49.913. + Executed 17 tests, with 0 failures (0 unexpected) in 0.003 (0.004) seconds +Test Suite 'CrossPlaneLinkTests' started at 2026-10-10 12:40:49.913. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testBasicLinkNoText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testBasicLinkNoText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinksFiltersOnlyMissingTargets]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinksFiltersOnlyMissingTargets]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinkTargetExistsFalse]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDanglingLinkTargetExistsFalse]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDecimalTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDecimalTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDocumentWithNoLinksReturnsEmpty]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testDocumentWithNoLinksReturnsEmpty]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testHexTargetIgnored]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testHexTargetIgnored]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphCollapsesRepeatedEdgesInEncounterOrder]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphCollapsesRepeatedEdgesInEncounterOrder]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphKeepsDanglingEdgeStatus]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkGraphKeepsDanglingEdgeStatus]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinksAcrossMultiplePlanesInSourceOrder]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinksAcrossMultiplePlanesInSourceOrder]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithEmptyText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithEmptyText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithText]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testLinkWithText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testMultipleLinksLeftToRight]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testMultipleLinksLeftToRight]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNanTargetIgnored]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNanTargetIgnored]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNegativeDecimalTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNegativeDecimalTarget]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNonDecimalTargetIgnored]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testNonDecimalTargetIgnored]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testOrdinaryMarkdownLinkNotExtracted]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testOrdinaryMarkdownLinkNotExtracted]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testScientificNotationTarget]' started. +Test Case '-[ThreeMDTests.CrossPlaneLinkTests testScientificNotationTarget]' passed (0.000 seconds). +Test Suite 'CrossPlaneLinkTests' passed at 2026-10-10 12:40:49.918. + Executed 17 tests, with 0 failures (0 unexpected) in 0.004 (0.005) seconds +Test Suite 'DocumentCompositionCodecTests' started at 2026-10-10 12:40:49.918. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCanonicalProfileStoresSharedDefinitionOnceAndIsOrderIndependent]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCanonicalProfileStoresSharedDefinitionOnceAndIsOrderIndependent]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCheckedInGrovePreservesItsSingleCanopyDefinitionAndBindingAcrossFormats]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testCheckedInGrovePreservesItsSingleCanopyDefinitionAndBindingAcrossFormats]' passed (0.011 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testJSONAllocationPreflightRejectsExcessiveArraysNestingAndTrailingBytes]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testJSONAllocationPreflightRejectsExcessiveArraysNestingAndTrailingBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileAndDefinitionBytePoliciesBoundBothReaderAndWriter]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileAndDefinitionBytePoliciesBoundBothReaderAndWriter]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileUsesGenericPortableBinaryEnvelopeWithoutAnotherFormat]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testProfileUsesGenericPortableBinaryEnvelopeWithoutAnotherFormat]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateDefinitionIDsAndUnusedMissingReferences]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateDefinitionIDsAndUnusedMissingReferences]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateJSONKeysIncludingEscapedSpelling]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsDuplicateJSONKeysIncludingEscapedSpelling]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsInvalidUnusedDefinitionsAndDoesNotLoadSourcePaths]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsInvalidUnusedDefinitionsAndDoesNotLoadSourcePaths]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsUnknownManifestEntryAndReferenceKeys]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRejectsUnknownManifestEntryAndReferenceKeys]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRequiresExactEnvelopeAndVersionedManifest]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReaderRequiresExactEnvelopeAndVersionedManifest]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReferenceAttributesPreserveControlsQuotesAndUnicodeWithoutBreakingFences]' started. +Test Case '-[ThreeMDTests.DocumentCompositionCodecTests testReferenceAttributesPreserveControlsQuotesAndUnicodeWithoutBreakingFences]' passed (0.002 seconds). +Test Suite 'DocumentCompositionCodecTests' passed at 2026-10-10 12:40:49.945. + Executed 11 tests, with 0 failures (0 unexpected) in 0.026 (0.027) seconds +Test Suite 'DocumentCompositionTests' started at 2026-10-10 12:40:49.945. +Test Case '-[ThreeMDTests.DocumentCompositionTests testCanceledConstructionAndStorageStayDistinctFromValidationErrors]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testCanceledConstructionAndStorageStayDistinctFromValidationErrors]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testCyclesAreRejectedInRootAndUnusedNodes]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testCyclesAreRejectedInRootAndUnusedNodes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDepthAndReferenceBudgetsHaveExactBoundarySemantics]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDepthAndReferenceBudgetsHaveExactBoundarySemantics]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDocumentPolicyIsIndependentOfCompositionPolicy]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testDefinitionDocumentPolicyIsIndependentOfCompositionPolicy]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testEveryDefinitionIsValidatedEvenWhenUnused]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testEveryDefinitionIsValidatedEvenWhenUnused]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testIDsAreCaseSensitiveAndNeverFileOrNetworkLocations]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testIDsAreCaseSensitiveAndNeverFileOrNetworkLocations]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testMissingRootMissingTargetAndDuplicateDefinitionsAreRejected]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testMissingRootMissingTargetAndDuplicateDefinitionsAreRejected]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testOccurrenceBudgetCountsSharedReferencesWithoutMaterializingThem]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testOccurrenceBudgetCountsSharedReferencesWithoutMaterializingThem]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testReferenceAttributesAreOpaqueUnicodeDataWithCountAndByteLimits]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testReferenceAttributesAreOpaqueUnicodeDataWithCountAndByteLimits]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testResourceLimitsCannotBeRaisedBeyondAbsoluteBounds]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testResourceLimitsCannotBeRaisedBeyondAbsoluteBounds]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testSharedNestedDefinitionsPreserveAxesMetadataAndReferenceOrder]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testSharedNestedDefinitionsPreserveAxesMetadataAndReferenceOrder]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testUniqueSourceByteBudgetCountsEachDefinitionOnce]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testUniqueSourceByteBudgetCountsEachDefinitionOnce]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentCompositionTests testUnusedDepthAndOccurrenceBudgetsAreAlsoEnforced]' started. +Test Case '-[ThreeMDTests.DocumentCompositionTests testUnusedDepthAndOccurrenceBudgetsAreAlsoEnforced]' passed (0.000 seconds). +Test Suite 'DocumentCompositionTests' passed at 2026-10-10 12:40:49.955. + Executed 13 tests, with 0 failures (0 unexpected) in 0.010 (0.010) seconds +Test Suite 'DocumentDiagnosticTests' started at 2026-10-10 12:40:49.955. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancellationIsNeverConvertedIntoAValidationDiagnostic]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancellationIsNeverConvertedIntoAValidationDiagnostic]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancelledCompositionDiagnosticsDoNotBeginPreflightOrGraphValidation]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCancelledCompositionDiagnosticsDoNotBeginPreflightOrGraphValidation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticBudgetRejectsBeforeExpensiveGraphSourceValidation]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticBudgetRejectsBeforeExpensiveGraphSourceValidation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticPreflightStillEnforcesCheapCountPolicies]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticPreflightStillEnforcesCheapCountPolicies]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticsScopeRepeatedInstanceIDsByOwner]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testCompositionDiagnosticsScopeRepeatedInstanceIDsByOwner]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticCeilingSignalsUninspectedRemainder]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticCeilingSignalsUninspectedRemainder]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticInputAndValueByteWorkAreBounded]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testDiagnosticInputAndValueByteWorkAreBounded]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testHostileLinkPrefixesDoNotTriggerLegacyRegexDuringDiagnostics]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testHostileLinkPrefixesDoNotTriggerLegacyRegexDuringDiagnostics]' passed (0.017 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSharedDecimalScannerRejectsLongMalformedLinkNumberAndPreservesGrammar]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSharedDecimalScannerRejectsLongMalformedLinkNumberAndPreservesGrammar]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSourceParseDiagnosticsPreserveRealLineEvidence]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testSourceParseDiagnosticsPreserveRealLineEvidence]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testValueDiagnosticsHavePlanePathsAndNoInventedLines]' started. +Test Case '-[ThreeMDTests.DocumentDiagnosticTests testValueDiagnosticsHavePlanePathsAndNoInventedLines]' passed (0.001 seconds). +Test Suite 'DocumentDiagnosticTests' passed at 2026-10-10 12:40:49.980. + Executed 11 tests, with 0 failures (0 unexpected) in 0.024 (0.025) seconds +Test Suite 'DocumentEditingTests' started at 2026-10-10 12:40:49.980. +Test Case '-[ThreeMDTests.DocumentEditingTests testAtomicCoordinateSwapRetainsIDsSourceOrderMetadataAndLegacyLinks]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testAtomicCoordinateSwapRetainsIDsSourceOrderMetadataAndLegacyLinks]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testCancelledTransactionPropagatesCancellation]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testCancelledTransactionPropagatesCancellation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testCanonicalReopenHasSameRevisionAndCodableValuesRoundTrip]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testCanonicalReopenHasSameRevisionAndCodableValuesRoundTrip]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testFailureAfterValidFirstOperationPublishesNothing]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testFailureAfterValidFirstOperationPublishesNothing]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testFinalCoordinateConflictReturnsPrecisePathAndNoMutation]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testFinalCoordinateConflictReturnsPrecisePathAndNoMutation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testInsertMoveRemoveAndHeaderTransactionPreservesUnrelatedPlanes]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testInsertMoveRemoveAndHeaderTransactionPreservesUnrelatedPlanes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidFinalDirectValuesCannotEscapeStorageValidation]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidFinalDirectValuesCannotEscapeStorageValidation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidInsertMoveAndDuplicateIdentityAreDiagnosed]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testInvalidInsertMoveAndDuplicateIdentityAreDiagnosed]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testNoIdentityLegacyDocumentRequiresExplicitAdoptionForTargetedEdits]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testNoIdentityLegacyDocumentRequiresExplicitAdoptionForTargetedEdits]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testOperationOperandAndExpectedRevisionBudgetsAreEnforced]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testOperationOperandAndExpectedRevisionBudgetsAreEnforced]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testReplacementCannotSilentlyChangeOrDropIdentity]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testReplacementCannotSilentlyChangeOrDropIdentity]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testSnapshotDecoderRejectsForgedRevision]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testSnapshotDecoderRejectsForgedRevision]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentEditingTests testStaleExactRevisionRejectsChangedContentAndUnicodeEquivalentBytes]' started. +Test Case '-[ThreeMDTests.DocumentEditingTests testStaleExactRevisionRejectsChangedContentAndUnicodeEquivalentBytes]' passed (0.000 seconds). +Test Suite 'DocumentEditingTests' passed at 2026-10-10 12:40:49.988. + Executed 13 tests, with 0 failures (0 unexpected) in 0.007 (0.008) seconds +Test Suite 'DocumentFileCompositionTests' started at 2026-10-10 12:40:49.988. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testAttributeBoundCountsNormalizedDirectoryPrefixBytes]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testAttributeBoundCountsNormalizedDirectoryPrefixBytes]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testBundledTextAndBinaryReopenWithoutSupplyingAnySourceFiles]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testBundledTextAndBinaryReopenWithoutSupplyingAnySourceFiles]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCachedSubtreeIsChargedAtItsDeeperOccurrenceAgainstTheDiscoveryCeiling]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCachedSubtreeIsChargedAtItsDeeperOccurrenceAgainstTheDiscoveryCeiling]' passed (0.250 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationDuringARunningFanOutResolutionPublishesNoResult]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationDuringARunningFanOutResolutionPublishesNoResult]' passed (1.161 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationStaysDistinctAndNeverReturnsPartialComposition]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancellationStaysDistinctAndNeverReturnsPartialComposition]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancelledPathResolutionPrecedesOversizedInput]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testCancelledPathResolutionPrecedesOversizedInput]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testChildStorageFailuresKeepOriginalErrorType]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testChildStorageFailuresKeepOriginalErrorType]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDisconnectedEmbeddedLedgerUsesActualEntryDepthAndRepeatedCachedFiles]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDisconnectedEmbeddedLedgerUsesActualEntryDepthAndRepeatedCachedFiles]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDiscoveryMissingFilePrecedesUnvalidatedFinalGraphDepth]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDiscoveryMissingFilePrecedesUnvalidatedFinalGraphDepth]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateBasenamesAndUnicodeScalarOrderingRemainDistinct]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateBasenamesAndUnicodeScalarOrderingRemainDistinct]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateNormalizedAndCanonicallyEquivalentSourcesFailBeforeDecode]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testDuplicateNormalizedAndCanonicallyEquivalentSourcesFailBeforeDecode]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingBundleRetainsUnusedEntriesOpaqueAttributesAndIdentitiesAndScansEveryLedger]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingBundleRetainsUnusedEntriesOpaqueAttributesAndIdentitiesAndScansEveryLedger]' passed (0.009 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingEdgesPrecedeLedgerEdgesAndEmbeddedLedgersResolveFromTheirBundleFolder]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testExistingEdgesPrecedeLedgerEdgesAndEmbeddedLedgersResolveFromTheirBundleFolder]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFileCyclesIncludeUnusedEmbeddedEntryLedgers]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFileCyclesIncludeUnusedEmbeddedEntryLedgers]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFixedFileDiscoverySafetyCeilingRemainsBoundedForDisconnectedEntries]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testFixedFileDiscoverySafetyCeilingRemainsBoundedForDisconnectedEntries]' passed (0.208 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerEscapesDecodeBeforePathGrammar]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerEscapesDecodeBeforePathGrammar]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerRejectsDuplicateEscapedKeysAndMalformedValuesAndGlyphs]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLedgerRejectsDuplicateEscapedKeysAndMalformedValuesAndGlyphs]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongDirectoryOwnersResolveRepeatedSourcesOnceAndRefuseOverBoundTargetsAtTheFirstEdge]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongDirectoryOwnersResolveRepeatedSourcesOnceAndRefuseOverBoundTargetsAtTheFirstEdge]' passed (1.608 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongOwnerPathWithManyReferencesResolvesEveryReferenceInItsDirectory]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLongOwnerPathWithManyReferencesResolvesEveryReferenceInItsDirectory]' passed (0.107 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredDefinitionDepthReferenceTraversalAndAttributePoliciesApplyToCompleteGraph]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredDefinitionDepthReferenceTraversalAndAttributePoliciesApplyToCompleteGraph]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredPolicyChargesOriginalPathBytesBeforePathGrammarAndEncodedBytesBeforeDecoding]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testLoweredPolicyChargesOriginalPathBytesBeforePathGrammarAndEncodedBytesBeforeDecoding]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testMissingRootAndLinkedChildReportNormalizedMissingPaths]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testMissingRootAndLinkedChildReportNormalizedMissingPaths]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedParentPathsAndRefreshedChildrenRetainDeterministicIDs]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedParentPathsAndRefreshedChildrenRetainDeterministicIDs]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedProfileUsesProfileRecordPolicyWhileOrdinaryAndChildDocumentsKeepTheirOwnPolicy]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testNestedProfileUsesProfileRecordPolicyWhileOrdinaryAndChildDocumentsKeepTheirOwnPolicy]' passed (0.006 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOnlyReachableSourcesDecode]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOnlyReachableSourcesDecode]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOuterRecognitionDoesNotUseCallerPlaneLimitBeforeByteAndLinePolicies]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOuterRecognitionDoesNotUseCallerPlaneLimitBeforeByteAndLinePolicies]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOverBoundLedgerEdgeIsRefusedWhileResolvingBeforeLaterRefusals]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOverBoundLedgerEdgeIsRefusedWhileResolvingBeforeLaterRefusals]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOwnerDirectoryResolutionKeepsParentDotAndGrammarSemantics]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testOwnerDirectoryResolutionKeepsParentDotAndGrammarSemantics]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testPathsNormalizeNFCAndParentsWithoutPercentDecoding]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testPathsNormalizeNFCAndParentsWithoutPercentDecoding]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testReachableEncodedByteAndSuppliedCountAndAggregatePathLimitsFailBeforeIndexingOrPublishing]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testReachableEncodedByteAndSuppliedCountAndAggregatePathLimitsFailBeforeIndexingOrPublishing]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRefusalsFollowEntryIDThenGlyphDiscoveryOrder]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRefusalsFollowEntryIDThenGlyphDiscoveryOrder]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRepeatedCachedFilesAreStillCheckedAgainstFinalCompleteEntryDepth]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRepeatedCachedFilesAreStillCheckedAgainstFinalCompleteEntryDepth]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testResolverOutputRebundlesWithOpaqueGlyphAndSourceFileAttributes]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testResolverOutputRebundlesWithOpaqueGlyphAndSourceFileAttributes]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRootAndUnreachableSuppliedPathsUseTheLedgerPathGrammar]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testRootAndUnreachableSuppliedPathsUseTheLedgerPathGrammar]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSelfAndAliasCyclesCompareNormalizedPaths]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSelfAndAliasCyclesCompareNormalizedPaths]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSimpleRepeatedFilesProduceOneDefinitionAndPreserveOrdinaryDocumentFields]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSimpleRepeatedFilesProduceOneDefinitionAndPreserveOrdinaryDocumentFields]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSourceFileAttributeBoundCountsNormalizedUTF8Bytes]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testSourceFileAttributeBoundCountsNormalizedUTF8Bytes]' passed (0.146 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testStandalonePathsAndLedgersPastTheOldRecordSizeAreSaved]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testStandalonePathsAndLedgersPastTheOldRecordSizeAreSaved]' passed (0.975 seconds). +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testTextAndUncompressedBinaryChildrenBundleIdenticallyWithoutExtensionRestrictions]' started. +Test Case '-[ThreeMDTests.DocumentFileCompositionTests testTextAndUncompressedBinaryChildrenBundleIdenticallyWithoutExtensionRestrictions]' passed (0.004 seconds). +Test Suite 'DocumentFileCompositionTests' passed at 2026-10-10 12:40:54.526. + Executed 39 tests, with 0 failures (0 unexpected) in 4.535 (4.538) seconds +Test Suite 'DocumentIdentityTests' started at 2026-10-10 12:40:54.526. +Test Case '-[ThreeMDTests.DocumentIdentityTests testAdoptionPreservesNamespaceMetadataAndDeterministicallySkipsExistingIDs]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testAdoptionPreservesNamespaceMetadataAndDeterministicallySkipsExistingIDs]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testCancelledIdentityAdoptionReturnsCancellation]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testCancelledIdentityAdoptionReturnsCancellation]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicateReferenceIdentityFailsWithinOwnerOnly]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicateReferenceIdentityFailsWithinOwnerOnly]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicatesAreRejectedRatherThanSilentlyRegenerated]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testDuplicatesAreRejectedRatherThanSilentlyRegenerated]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testExplicitIdentitiesRoundTripThroughTextAndBothBinaryBackends]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testExplicitIdentitiesRoundTripThroughTextAndBothBinaryBackends]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testIdentityAdoptionRespectsDocumentAndReferenceAttributeBudgets]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testIdentityAdoptionRespectsDocumentAndReferenceAttributeBudgets]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testRepeatedTargetsGainIndependentOwnerScopedReferenceIDs]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testRepeatedTargetsGainIndependentOwnerScopedReferenceIDs]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentIdentityTests testUnsafeAndEmptyExistingIDsAreRejectedWithExactPaths]' started. +Test Case '-[ThreeMDTests.DocumentIdentityTests testUnsafeAndEmptyExistingIDsAreRejectedWithExactPaths]' passed (0.001 seconds). +Test Suite 'DocumentIdentityTests' passed at 2026-10-10 12:40:54.534. + Executed 8 tests, with 0 failures (0 unexpected) in 0.008 (0.008) seconds +Test Suite 'DocumentStorageBoundsTests' started at 2026-10-10 12:40:54.534. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testADocumentPastTheOldCeilingRoundTrips]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testADocumentPastTheOldCeilingRoundTrips]' passed (19.038 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCanceledTasksCannotReturnPartiallyEncodedOrDecodedDocuments]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCanceledTasksCannotReturnPartiallyEncodedOrDecodedDocuments]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCombinedScalarAndDirectiveBytesCannotBypassTheOutputBound]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testCombinedScalarAndDirectiveBytesCannotBypassTheOutputBound]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testLimitsArePositiveAndHaveNoAbsoluteCeiling]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testLimitsArePositiveAndHaveNoAbsoluteCeiling]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPhysicalLinesAreBoundedBeforeParsingEvenForBlankInputs]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPhysicalLinesAreBoundedBeforeParsingEvenForBlankInputs]' passed (0.009 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPlanePreflightIgnoresDirectivesInsideBothKindsOfFences]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testPlanePreflightIgnoresDirectivesInsideBothKindsOfFences]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testRecordBoundIncludesWholePlaneBodiesAndEscapedScalarLines]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testRecordBoundIncludesWholePlaneBodiesAndEscapedScalarLines]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testTextAndPortableBinaryAcceptExactByteBounds]' started. +Test Case '-[ThreeMDTests.DocumentStorageBoundsTests testTextAndPortableBinaryAcceptExactByteBounds]' passed (0.001 seconds). +Test Suite 'DocumentStorageBoundsTests' passed at 2026-10-10 12:41:13.584. + Executed 8 tests, with 0 failures (0 unexpected) in 19.050 (19.050) seconds +Test Suite 'DocumentStorageCompressionTests' started at 2026-10-10 12:41:13.584. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testAppleLZFSECompressionIsDeterministicAndRoundTripsGeneralText]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testAppleLZFSECompressionIsDeterministicAndRoundTripsGeneralText]' passed (0.144 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testCanceledCompressionAndDecompressionRemainCancellationErrors]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testCanceledCompressionAndDecompressionRemainCancellationErrors]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testDeclaredOutputSizeCannotTruncateOrGrowDecompression]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testDeclaredOutputSizeCannotTruncateOrGrowDecompression]' passed (0.030 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testEveryTruncationAndMalformedCompressionPayloadFailsWithoutPartialResults]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testEveryTruncationAndMalformedCompressionPayloadFailsWithoutPartialResults]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLargeFirstStreamDrainsMultipleChunksBeforeFinalMarkerAndRejectsConcatenation]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLargeFirstStreamDrainsMultipleChunksBeforeFinalMarkerAndRejectsConcatenation]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLZFSERejectsTrailingAndConcatenatedStreamsWithValidChecksums]' started. +Test Case '-[ThreeMDTests.DocumentStorageCompressionTests testLZFSERejectsTrailingAndConcatenatedStreamsWithValidChecksums]' passed (0.000 seconds). +Test Suite 'DocumentStorageCompressionTests' passed at 2026-10-10 12:41:13.768. + Executed 6 tests, with 0 failures (0 unexpected) in 0.183 (0.184) seconds +Test Suite 'DocumentStorageDecimalTests' started at 2026-10-10 12:41:13.768. +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testCancellationDuringAnInvalidParseRemainsCancellationError]' started. +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testCancellationDuringAnInvalidParseRemainsCancellationError]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testLongMalformedDecimalRejectsReadableAndChecksummedBinaryWithoutBacktracking]' started. +Test Case '-[ThreeMDTests.DocumentStorageDecimalTests testLongMalformedDecimalRejectsReadableAndChecksummedBinaryWithoutBacktracking]' passed (0.002 seconds). +Test Suite 'DocumentStorageDecimalTests' passed at 2026-10-10 12:41:13.772. + Executed 2 tests, with 0 failures (0 unexpected) in 0.004 (0.004) seconds +Test Suite 'DocumentStorageStructuredTests' started at 2026-10-10 12:41:13.772. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testAmplifiedQuotedKeysAreRejectedByPhaseLBeforeAnyPhaseQParse]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testAmplifiedQuotedKeysAreRejectedByPhaseLBeforeAnyPhaseQParse]' passed (0.395 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanceledTasksReturnNoStructuredDocumentOrBytes]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanceledTasksReturnNoStructuredDocumentOrBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCancellationIsCheckedAtEveryStructuredCheckpoint]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCancellationIsCheckedAtEveryStructuredCheckpoint]' passed (0.955 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanonicallyEquivalentKeysInOnePayloadMapAreInvalidDocuments]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCanonicallyEquivalentKeysInOnePayloadMapAreInvalidDocuments]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChecksumSlicingMatchesTheBytewiseDefinitionAtEveryAlignment]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChecksumSlicingMatchesTheBytewiseDefinitionAtEveryAlignment]' passed (1.673 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChunkedUTF8ValidationAgreesWithWholeValidationAcrossChunkBoundaries]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testChunkedUTF8ValidationAgreesWithWholeValidationAcrossChunkBoundaries]' passed (0.465 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testConcurrentTasksEncodeAndDecodeIndependently]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testConcurrentTasksEncodeAndDecodeIndependently]' passed (0.018 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testContainerInfoReportsRawHeaderFieldsWithoutValidation]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testContainerInfoReportsRawHeaderFieldsWithoutValidation]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCountFramingDividesAndPrecedesThePlaneLimitAtTheLargestCounts]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testCountFramingDividesAndPrecedesThePlaneLimitAtTheLargestCounts]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodeAcceptsDataSlicesWithANonzeroStartIndex]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodeAcceptsDataSlicesWithANonzeroStartIndex]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodedLengthBoundPrecedesTheChecksumAndDecompression]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodedLengthBoundPrecedesTheChecksumAndDecompression]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodingPeakMemoryGrowthStaysUnderThreeTimesTheInput]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testDecodingPeakMemoryGrowthStaysUnderThreeTimesTheInput]' passed (29.619 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEightyEmptyPlanesDecodeUnderAnEncodedLimitTheirTextWouldExceed]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEightyEmptyPlanesDecodeUnderAnEncodedLimitTheirTextWouldExceed]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryGoldenIsByteIdenticalAndDecodesToTheBoundedTextDecode]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryGoldenIsByteIdenticalAndDecodesToTheBoundedTextDecode]' passed (0.067 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryVectorReportsItsCodeUnderItsLimits]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testEveryVectorReportsItsCodeUnderItsLimits]' passed (0.019 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testFrozenWhitespaceSetHoldsExactlyNineteenScalars]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testFrozenWhitespaceSetHoldsExactlyNineteenScalars]' passed (0.267 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testKeysAreOrderedByUTF8BytesWhichIsCodePointOrder]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testKeysAreOrderedByUTF8BytesWhichIsCodePointOrder]' passed (0.007 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLongAttributeKeysAreComparedWithTheirLowercaseAcrossChunkEdges]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLongAttributeKeysAreComparedWithTheirLowercaseAcrossChunkEdges]' passed (0.233 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredPayloadsRoundTripAndKeepTheDecodedBound]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredPayloadsRoundTripAndKeepTheDecodedBound]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredStreamsMustEndOnceAndMatchTheDeclaredLength]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testLZFSEStructuredStreamsMustEndOnceAndMatchTheDeclaredLength]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtEveryExampleLimitEdge]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtEveryExampleLimitEdge]' passed (1.244 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtTheLimitEdgesOfGeneratedDocuments]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMetricsMatchTheTextWriterAtTheLimitEdgesOfGeneratedDocuments]' passed (9.797 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMutatedFilesGiveOneTypedOutcomeAndAcceptedOnesAreCanonical]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testMutatedFilesGiveOneTypedOutcomeAndAcceptedOnesAreCanonical]' passed (3.205 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumberFormsFollowTheCanonicalTableAndDecodeBitExactly]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumberFormsFollowTheCanonicalTableAndDecodeBitExactly]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumericPowersSpellAsTheSharedCanonicalNumbersAndRoundTripBitExactly]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testNumericPowersSpellAsTheSharedCanonicalNumbersAndRoundTripBitExactly]' passed (0.174 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testRandomBitPatternsTakeTheirCanonicalFormAndRoundTripBitExactly]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testRandomBitPatternsTakeTheirCanonicalFormAndRoundTripBitExactly]' passed (2.260 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesAgreeWithTheTextParserOnRandomBodies]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesAgreeWithTheTextParserOnRandomBodies]' passed (7.509 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesMatchTheTextRoundTripOnHandCases]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSegmentRulesMatchTheTextRoundTripOnHandCases]' passed (0.007 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testShortStringsChargeTheCancellationBudgetInEveryPass]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testShortStringsChargeTheCancellationBudgetInEveryPass]' passed (1.775 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSizeGateHoldsForEveryExampleAndTheCorpus]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testSizeGateHoldsForEveryExampleAndTheCorpus]' passed (0.622 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testTextContainerWriterKeepsTheTwoZeroBytesAndHeaderChecks]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testTextContainerWriterKeepsTheTwoZeroBytesAndHeaderChecks]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUnicodeSkewVectorsFollowTheRuntimeUnicodeData]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUnicodeSkewVectorsFollowTheRuntimeUnicodeData]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUTF8ValidityIsRepairedDecodingThatEqualsTheInputBytes]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testUTF8ValidityIsRepairedDecodingThatEqualsTheInputBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testVarEncodesMinimallyAndDecodesEveryBoundary]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testVarEncodesMinimallyAndDecodesEveryBoundary]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWorkedExamplesHoldTheBytesAndChecksumsOfTheSpecification]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWorkedExamplesHoldTheBytesAndChecksumsOfTheSpecification]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterAcceptanceEqualsValidationAndDecodeEqualsTheTextDecode]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterAcceptanceEqualsValidationAndDecodeEqualsTheTextDecode]' passed (3.227 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterCapsTheUncompressedContainerAtTheEncodedLimit]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterCapsTheUncompressedContainerAtTheEncodedLimit]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterOutputDecodesUnderTheSameLimitsToTheNormalizedDocument]' started. +Test Case '-[ThreeMDTests.DocumentStorageStructuredTests testWriterOutputDecodesUnderTheSameLimitsToTheNormalizedDocument]' passed (0.406 seconds). +Test Suite 'DocumentStorageStructuredTests' passed at 2026-10-10 12:42:17.736. + Executed 38 tests, with 0 failures (0 unexpected) in 63.960 (63.964) seconds +Test Suite 'DocumentStorageTests' started at 2026-10-10 12:42:17.736. +Test Case '-[ThreeMDTests.DocumentStorageTests testAllHeaderFieldsAndCorruptionAreChecked]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testAllHeaderFieldsAndCorruptionAreChecked]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testBinaryDecodeHandlesDataSlices]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testBinaryDecodeHandlesDataSlices]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInCompressedCanopyRoundTripsToItsReadableDocument]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInCompressedCanopyRoundTripsToItsReadableDocument]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInExtensionManifestDescribesTheActualSixArtifacts]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInExtensionManifestDescribesTheActualSixArtifacts]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInPortableCanopyRoundTripsToItsReadableDocument]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testCheckedInPortableCanopyRoundTripsToItsReadableDocument]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testContainerPayloadMustBeValidUTF8AndThreeMDText]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testContainerPayloadMustBeValidUTF8AndThreeMDText]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testDirectDocumentValidationRejectsLossyOrAmbiguousSerialization]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testDirectDocumentValidationRejectsLossyOrAmbiguousSerialization]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testGeneralDocumentsPreserveUnicodeCustomAxesAndFractionalPositions]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testGeneralDocumentsPreserveUnicodeCustomAxesAndFractionalPositions]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testPortableContainerFixedVector]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testPortableContainerFixedVector]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.DocumentStorageTests testStorageRetainsTextGrammarAndLegacySerializerPreservesLiteralQuotes]' started. +Test Case '-[ThreeMDTests.DocumentStorageTests testStorageRetainsTextGrammarAndLegacySerializerPreservesLiteralQuotes]' passed (0.000 seconds). +Test Suite 'DocumentStorageTests' passed at 2026-10-10 12:42:17.745. + Executed 10 tests, with 0 failures (0 unexpected) in 0.008 (0.009) seconds +Test Suite 'ExtensionConformanceTests' started at 2026-10-10 12:42:17.745. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testCanonicalNumericBitPatternsMatchSharedSwiftFormattingVectors]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testCanonicalNumericBitPatternsMatchSharedSwiftFormattingVectors]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testDocumentEnvelopeAndProfileGoldensMatchExactCanonicalBytes]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testDocumentEnvelopeAndProfileGoldensMatchExactCanonicalBytes]' passed (0.011 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedBinaryChecksumGoldensRejectCorruption]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedBinaryChecksumGoldensRejectCorruption]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedCompositionTransactionsKeepUnchangedDefinitionsAndRepeatedInstances]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedCompositionTransactionsKeepUnchangedDefinitionsAndRepeatedInstances]' passed (0.010 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedDocumentTransactionsValidateFinalValuesAtomically]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedDocumentTransactionsValidateFinalValuesAtomically]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedFailedTransactionsHaveStableCodesPathsAndNoPartialPublication]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedFailedTransactionsHaveStableCodesPathsAndNoPartialPublication]' passed (0.008 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedIdentityAdoptionPreservesOpaqueFieldsAndOwnerScopes]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testSharedIdentityAdoptionPreservesOpaqueFieldsAndOwnerScopes]' passed (0.004 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testStrictCompositionJSONRejectsCanonicallyEquivalentDuplicateKeys]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testStrictCompositionJSONRejectsCanonicallyEquivalentDuplicateKeys]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeKeyOrderingGoldensPreserveOriginalSpellingAndExactBytes]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeKeyOrderingGoldensPreserveOriginalSpellingAndExactBytes]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeSourceKeyCollisionsKeepFirstSpellingAndLastValue]' started. +Test Case '-[ThreeMDTests.ExtensionConformanceTests testUnicodeSourceKeyCollisionsKeepFirstSpellingAndLastValue]' passed (0.001 seconds). +Test Suite 'ExtensionConformanceTests' passed at 2026-10-10 12:42:17.792. + Executed 10 tests, with 0 failures (0 unexpected) in 0.046 (0.047) seconds +Test Suite 'HTMLRendererTests' started at 2026-10-10 12:42:17.792. +Test Case '-[ThreeMDTests.HTMLRendererTests testAmpersandEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testAmpersandEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testAxisEmittedInMeta]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testAxisEmittedInMeta]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testBodyRenderedAsMarkdown]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testBodyRenderedAsMarkdown]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testDecimalZInDataAttribute]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testDecimalZInDataAttribute]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testDoubleQuoteEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testDoubleQuoteEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelRenderedAsHeading]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelRenderedAsHeading]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelSpecialCharsEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testLabelSpecialCharsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testLessThanEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testLessThanEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testMissingTitleFallsBackToDefault]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testMissingTitleFallsBackToDefault]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputContainsHeadAndBody]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputContainsHeadAndBody]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputIsStandaloneHTML]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testOutputIsStandaloneHTML]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testPlaneCountMatchesSections]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testPlaneCountMatchesSections]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testPreambleRenderedInSection]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testPreambleRenderedInSection]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesAriaLabel]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesAriaLabel]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesDataZ]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testSectionCarriesDataZ]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testSingleQuoteEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testSingleQuoteEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInH1]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInH1]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInTitleElement]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleEmittedInTitleElement]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleSpecialCharsEscaped]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testTitleSpecialCharsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.HTMLRendererTests testVersionEmittedInMeta]' started. +Test Case '-[ThreeMDTests.HTMLRendererTests testVersionEmittedInMeta]' passed (0.000 seconds). +Test Suite 'HTMLRendererTests' passed at 2026-10-10 12:42:17.797. + Executed 20 tests, with 0 failures (0 unexpected) in 0.004 (0.005) seconds +Test Suite 'InterchangeConformanceTests' started at 2026-10-10 12:42:17.797. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testAdoptionAndDeterministicDocumentEditsHaveExactRevisionAndRejectReuse]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testAdoptionAndDeterministicDocumentEditsHaveExactRevisionAndRejectReuse]' passed (0.040 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testASCIIFencePrefixesWithCombiningMarksKeepInnerDirectivesAsBody]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testASCIIFencePrefixesWithCombiningMarksKeepInnerDirectivesAsBody]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogIncludesEveryDeclaredExtensionSourceAndBinaryGolden]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogIncludesEveryDeclaredExtensionSourceAndBinaryGolden]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogRequiresEveryLegacySourceAndHasUniqueCompleteCases]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCatalogRequiresEveryLegacySourceAndHasUniqueCompleteCases]' passed (0.039 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCombiningMarkEscapesChargeExactCanonicalUTF8OutputBytes]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testCombiningMarkEscapesChargeExactCanonicalUTF8OutputBytes]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryInvalidCatalogSourceReportsItsRequiredTypedError]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryInvalidCatalogSourceReportsItsRequiredTypedError]' passed (0.006 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryValidCatalogSourceAndLegacyOutputPreserveExactCanonicalBytes]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testEveryValidCatalogSourceAndLegacyOutputPreserveExactCanonicalBytes]' passed (0.052 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testLegacySerializerPreservesRepresentableScalarQuotesAndFoundationEdgeWhitespace]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testLegacySerializerPreservesRepresentableScalarQuotesAndFoundationEdgeWhitespace]' passed (0.003 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarFieldSeparatorsAndSpaceTokensMatchBoundedPreflight]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarFieldSeparatorsAndSpaceTokensMatchBoundedPreflight]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarQuoteAndEscapeDelimitersPreserveAdjacentCombiningMarks]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testScalarQuoteAndEscapeDelimitersPreserveAdjacentCombiningMarks]' passed (0.002 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testSharedDAGAndUnusedDefinitionsSurviveAdoptionAndRootReplacement]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testSharedDAGAndUnusedDefinitionsSurviveAdoptionAndRootReplacement]' passed (0.005 seconds). +Test Case '-[ThreeMDTests.InterchangeConformanceTests testStorageRejectsReservedASCIIDelimitersInsideCombiningGraphemes]' started. +Test Case '-[ThreeMDTests.InterchangeConformanceTests testStorageRejectsReservedASCIIDelimitersInsideCombiningGraphemes]' passed (0.000 seconds). +Test Suite 'InterchangeConformanceTests' passed at 2026-10-10 12:42:17.946. + Executed 12 tests, with 0 failures (0 unexpected) in 0.149 (0.149) seconds +Test Suite 'MarkdownRendererTests' started at 2026-10-10 12:42:17.946. +Test Case '-[ThreeMDTests.MarkdownRendererTests testAmpersandInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testAmpersandInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlankLineSeparatesParagraphs]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlankLineSeparatesParagraphs]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlockquote]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBlockquote]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleAsterisk]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleAsterisk]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleUnderscore]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldDoubleUnderscore]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldMidSentence]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testBoldMidSentence]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemLowercase]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemLowercase]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemUppercase]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testCheckedTaskItemUppercase]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testDoubleQuoteInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testDoubleQuoteInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlock]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlock]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockEscapesHTML]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockEscapesHTML]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockPreservesMarkdownLookingContent]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockPreservesMarkdownLookingContent]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockWithLanguage]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testFencedCodeBlockWithLanguage]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH1]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH1]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH2]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH2]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH3]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH3]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH4]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH4]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH5]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH5]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testH6]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testH6]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingFollowedByParagraph]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingFollowedByParagraph]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingRequiresSpaceAfterHash]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testHeadingRequiresSpaceAfterHash]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCode]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCode]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeDoesNotRenderMarkdown]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeDoesNotRenderMarkdown]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeEscapesHTML]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testInlineCodeEscapesHTML]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicAsterisk]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicAsterisk]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicUnderscore]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testItalicUnderscore]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLessThanInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLessThanInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLink]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLink]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkHrefIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkHrefIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkTextIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testLinkTextIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineBlockquote]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineBlockquote]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineParagraphJoinsWithSpace]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testMultiLineParagraphJoinsWithSpace]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testOrderedList]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testOrderedList]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testParagraphWithBoldAndLink]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testParagraphWithBoldAndLink]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleLineParagraph]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleLineParagraph]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleQuoteInParagraphIsEscaped]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testSingleQuoteInParagraphIsEscaped]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testUncheckedTaskItem]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testUncheckedTaskItem]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListAsterisk]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListAsterisk]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListDash]' started. +Test Case '-[ThreeMDTests.MarkdownRendererTests testUnorderedListDash]' passed (0.000 seconds). +Test Suite 'MarkdownRendererTests' passed at 2026-10-10 12:42:17.953. + Executed 39 tests, with 0 failures (0 unexpected) in 0.005 (0.007) seconds +Test Suite 'ParseErrorMetadataTests' started at 2026-10-10 12:42:17.953. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testDuplicatePlaneMetadata]' started. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testDuplicatePlaneMetadata]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testInvalidDirectiveMetadata]' started. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testInvalidDirectiveMetadata]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testMissingVersionCode]' started. +Test Case '-[ThreeMDTests.ParseErrorMetadataTests testMissingVersionCode]' passed (0.000 seconds). +Test Suite 'ParseErrorMetadataTests' passed at 2026-10-10 12:42:17.954. + Executed 3 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds +Test Suite 'ParserNumericTests' started at 2026-10-10 12:42:17.954. +Test Case '-[ThreeMDTests.ParserNumericTests testFiniteDecimalGrammarIsPreservedForEveryCoordinate]' started. +Test Case '-[ThreeMDTests.ParserNumericTests testFiniteDecimalGrammarIsPreservedForEveryCoordinate]' passed (0.001 seconds). +Test Case '-[ThreeMDTests.ParserNumericTests testMalformedAndNonfiniteNumbersAreRejectedForEveryCoordinate]' started. +Test Case '-[ThreeMDTests.ParserNumericTests testMalformedAndNonfiniteNumbersAreRejectedForEveryCoordinate]' passed (0.001 seconds). +Test Suite 'ParserNumericTests' passed at 2026-10-10 12:42:17.956. + Executed 2 tests, with 0 failures (0 unexpected) in 0.002 (0.002) seconds +Test Suite 'ParserTests' started at 2026-10-10 12:42:17.956. +Test Case '-[ThreeMDTests.ParserTests testAxisDefaultsToLayer]' started. +Test Case '-[ThreeMDTests.ParserTests testAxisDefaultsToLayer]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testAxisRawValueNormalized]' started. +Test Case '-[ThreeMDTests.ParserTests testAxisRawValueNormalized]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testDecimalZValue]' started. +Test Case '-[ThreeMDTests.ParserTests testDecimalZValue]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testDuplicatePositionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testDuplicatePositionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testEmptyDocumentProducesNoPlanes]' started. +Test Case '-[ThreeMDTests.ParserTests testEmptyDocumentProducesNoPlanes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testFrontmatterIgnoresCommentLines]' started. +Test Case '-[ThreeMDTests.ParserTests testFrontmatterIgnoresCommentLines]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testFrontmatterStripsQuotedValues]' started. +Test Case '-[ThreeMDTests.ParserTests testFrontmatterStripsQuotedValues]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testInvalidDirectiveTokenThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testInvalidDirectiveTokenThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testKnownAxesMatchSpec]' started. +Test Case '-[ThreeMDTests.ParserTests testKnownAxesMatchSpec]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testLeadingBlankLinesBeforeFrontmatter]' started. +Test Case '-[ThreeMDTests.ParserTests testLeadingBlankLinesBeforeFrontmatter]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testMissingFrontmatterThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testMissingFrontmatterThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testMissingPlanePositionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testMissingPlanePositionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testMissingVersionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testMissingVersionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNegativeZValue]' started. +Test Case '-[ThreeMDTests.ParserTests testNegativeZValue]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNonNumericPositionThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testNonNumericPositionThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNonNumericXThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testNonNumericXThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testNonNumericYThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testNonNumericYThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParseErrorDescriptions]' started. +Test Case '-[ThreeMDTests.ParserTests testParseErrorDescriptions]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParsesFrontmatter]' started. +Test Case '-[ThreeMDTests.ParserTests testParsesFrontmatter]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParsesMultiplePlanes]' started. +Test Case '-[ThreeMDTests.ParserTests testParsesMultiplePlanes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testParsesPlaneCoordinatesAndAttributes]' started. +Test Case '-[ThreeMDTests.ParserTests testParsesPlaneCoordinatesAndAttributes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlainMarkdownBecomesSinglePlane]' started. +Test Case '-[ThreeMDTests.ParserTests testPlainMarkdownBecomesSinglePlane]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlaneAtZReturnsNilForMissingPosition]' started. +Test Case '-[ThreeMDTests.ParserTests testPlaneAtZReturnsNilForMissingPosition]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlaneBodyTrimsLeadingAndTrailingBlanks]' started. +Test Case '-[ThreeMDTests.ParserTests testPlaneBodyTrimsLeadingAndTrailingBlanks]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPlanesByZAreSorted]' started. +Test Case '-[ThreeMDTests.ParserTests testPlanesByZAreSorted]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testPreambleBeforeFirstPlane]' started. +Test Case '-[ThreeMDTests.ParserTests testPreambleBeforeFirstPlane]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testReservedAttributeKeysNotInExtras]' started. +Test Case '-[ThreeMDTests.ParserTests testReservedAttributeKeysNotInExtras]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testRoundTripThroughSerializer]' started. +Test Case '-[ThreeMDTests.ParserTests testRoundTripThroughSerializer]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithMetadataAndAttributes]' started. +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithMetadataAndAttributes]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithPreamble]' started. +Test Case '-[ThreeMDTests.ParserTests testRoundTripWithPreamble]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testUnclosedFrontmatterThrows]' started. +Test Case '-[ThreeMDTests.ParserTests testUnclosedFrontmatterThrows]' passed (0.000 seconds). +Test Case '-[ThreeMDTests.ParserTests testWindowsLineEndingsNormalized]' started. +Test Case '-[ThreeMDTests.ParserTests testWindowsLineEndingsNormalized]' passed (0.000 seconds). +Test Suite 'ParserTests' passed at 2026-10-10 12:42:17.963. + Executed 32 tests, with 0 failures (0 unexpected) in 0.005 (0.007) seconds +Test Suite '3mdPackageTests.xctest' passed at 2026-10-10 12:42:17.963. + Executed 322 tests, with 0 failures (0 unexpected) in 88.077 (88.100) seconds +Test Suite 'All tests' passed at 2026-10-10 12:42:17.963. + Executed 322 tests, with 0 failures (0 unexpected) in 88.077 (88.101) seconds +◇ Test run started. +↳ Testing Library Version: 1902 +↳ Target Platform: arm64e-apple-macos14.0 +✔ Test run with 0 tests in 0 suites passed after 0.001 seconds. + ✔ Step 3 done (1m 28.937s) + ▶️ Running task: js +bun install v1.4.0 (34cbb9a40) + +Checked 5 installs across 6 packages (no changes) [24.00ms] +$ tsc --noEmit +$ bun build ./src/index.ts --outdir ./dist --target node --format esm && tsc -p tsconfig.build.json +Bundled 9 modules in 15ms + + index.js 146.91 KB (entry point) + +bun test v1.4.0 (34cbb9a40) + +test/interchange.test.ts: +(pass) lossless cross-language interchange > raw parsing and bounded decoding use the literal Foundation whitespace set [19.19ms] +(pass) lossless cross-language interchange > Unicode whitespace fences do not invent directives during bounded preflight [1.87ms] +(pass) lossless cross-language interchange > UTF-8 decoding leaves BOM removal to the parser exactly once [0.20ms] +(pass) lossless cross-language interchange > source dictionary collisions retain first spelling and the last assignment in source order [7.42ms] +(pass) lossless cross-language interchange > legacy serialization preserves literal apostrophes, edge whitespace, quotes and backslashes [1.26ms] +(pass) lossless cross-language interchange > legacy number formatting and Unicode scalar key order agree with canonical wire writers [0.85ms] +(pass) lossless cross-language interchange > links preserve long finite targets, long labels and multiline labels [0.33ms] +(pass) lossless cross-language interchange > linear link scanning preserves reference regex matching for malformed nested candidates [1.71ms] + +test/structured.test.ts: +(pass) structured goldens (test-plan section 1) > the manifest lists 49 interchange anchors, 2 examples and 3 worked examples [0.07ms] +(pass) structured goldens (test-plan section 1) > axis-48: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [3.71ms] +(pass) structured goldens (test-plan section 1) > axis-49: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.60ms] +(pass) structured goldens (test-plan section 1) > axis-50: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.34ms] +(pass) structured goldens (test-plan section 1) > axis-51: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.36ms] +(pass) structured goldens (test-plan section 1) > axis-52: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.35ms] +(pass) structured goldens (test-plan section 1) > axis-53: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.30ms] +(pass) structured goldens (test-plan section 1) > axis-54: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.28ms] +(pass) structured goldens (test-plan section 1) > axis-55: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.61ms] +(pass) structured goldens (test-plan section 1) > axis-56: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.42ms] +(pass) structured goldens (test-plan section 1) > axis-57: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.26ms] +(pass) structured goldens (test-plan section 1) > combining-mark-delimiters: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [1.54ms] +(pass) structured goldens (test-plan section 1) > combining-mark-fences: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.47ms] +(pass) structured goldens (test-plan section 1) > combining-mark-scalars: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [1.57ms] +(pass) structured goldens (test-plan section 1) > composition-empty-root: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [4.25ms] +(pass) structured goldens (test-plan section 1) > composition-shared-dag-unused: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [7.62ms] +(pass) structured goldens (test-plan section 1) > empty-document: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.28ms] +(pass) structured goldens (test-plan section 1) > empty-planes: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [1.12ms] +(pass) structured goldens (test-plan section 1) > extension-composition-instances: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [4.98ms] +(pass) structured goldens (test-plan section 1) > extension-document-unicode: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.86ms] +(pass) structured goldens (test-plan section 1) > extension-unicode-key-order: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [1.11ms] +(pass) structured goldens (test-plan section 1) > extension-unicode-source-collision: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.42ms] +(pass) structured goldens (test-plan section 1) > fences-and-directives: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.39ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-attribute-numeric-stays-string: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.17ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-axis-default: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.17ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-axis-lowercased: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.12ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-bom: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.14ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-code-block-directive-safe: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.14ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-coordinates-attributes: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.25ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-crlf: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.16ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-decimal-negative-z: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.16ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-empty-body: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.09ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-empty-plane-body: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.12ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-escaped-quote-label: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.14ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-frontmatter-comments: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.20ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-indented-directive-is-body: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.16ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-leading-blank-lines: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.18ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-metadata-key-case-preserved: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.15ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-multi-plane: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.33ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-plane-prefix-not-directive: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.14ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-preamble-with-planes: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.24ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-repeated-directive-key-last-wins: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.16ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-single-plane-shorthand: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.14ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-version-1-0: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.12ms] +(pass) structured goldens (test-plan section 1) > legacy-valid-z-scientific-notation: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.18ms] +(pass) structured goldens (test-plan section 1) > mixed-coordinates: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.27ms] +(pass) structured goldens (test-plan section 1) > nfc-source-keys: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.24ms] +(pass) structured goldens (test-plan section 1) > scalar-quoting: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.42ms] +(pass) structured goldens (test-plan section 1) > unicode-exact-values: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.47ms] +(pass) structured goldens (test-plan section 1) > whitespace-crlf-bom: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.15ms] +(pass) structured goldens (test-plan section 1) > canopy: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.39ms] +(pass) structured goldens (test-plan section 1) > shared-grove: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [3.16ms] +(pass) structured goldens (test-plan section 1) > worked-document: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.27ms] +(pass) structured goldens (test-plan section 1) > worked-numbers: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.17ms] +(pass) structured goldens (test-plan section 1) > worked-keys: writer bytes, decode, re-encode, header, kind-1 sibling, SHA-256 [0.22ms] +(pass) structured goldens (test-plan section 1) > the worked document has the metrics of SPEC.md 11.3.17 and the annotated bytes [1.04ms] +(pass) structured vectors (test-plan section 2) > the manifest holds 156 vectors: 30 with limits, 25 ok, 131 typed errors [0.13ms] +(pass) structured vectors (test-plan section 2) > container-truncated-header (D4) gives invalidContainer [0.17ms] +(pass) structured vectors (test-plan section 2) > container-version-2 (D5) gives unsupportedVersion [0.04ms] +(pass) structured vectors (test-plan section 2) > container-kind-0 (D6) gives unsupportedPayloadKind [0.03ms] +(pass) structured vectors (test-plan section 2) > container-kind-3 (D6) gives unsupportedPayloadKind [0.03ms] +(pass) structured vectors (test-plan section 2) > container-kind-4 (D6) gives unsupportedPayloadKind [0.07ms] +(pass) structured vectors (test-plan section 2) > container-kind-255 (D6) gives unsupportedPayloadKind [0.04ms] +(pass) structured vectors (test-plan section 2) > container-kind-3-bad-crc (D6) gives unsupportedPayloadKind [0.03ms] +(pass) structured vectors (test-plan section 2) > container-compression-2 (D7) gives unsupportedCompression [0.03ms] +(pass) structured vectors (test-plan section 2) > container-flags (D8) gives unsupportedFlags [0.02ms] +(pass) structured vectors (test-plan section 2) > container-reserved (D9) gives nonzeroReserved [0.02ms] +(pass) structured vectors (test-plan section 2) > container-decoded-over-emax (D10) gives oversizedOutput [0.04ms] +(pass) structured vectors (test-plan section 2) > container-decoded-over-2dmax-bad-crc (D10) gives oversizedOutput [0.03ms] +(pass) structured vectors (test-plan section 2) > container-encoded-zero (D11) gives lengthMismatch [0.02ms] +(pass) structured vectors (test-plan section 2) > container-decoded-zero (D11) gives lengthMismatch [0.02ms] +(pass) structured vectors (test-plan section 2) > container-encoded-mismatch (D11) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > container-uncompressed-lengths-differ (D11) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > container-trailing-byte (D11) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > container-crc-field (D12) gives checksumMismatch [0.02ms] +(pass) structured vectors (test-plan section 2) > container-crc-payload (D12) gives checksumMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > container-lzfse-portable (D13) gives compressionUnavailable [0.20ms] +(pass) structured vectors (test-plan section 2) > var-non-minimal (V3) gives invalidContainer [0.07ms] +(pass) structured vectors (test-plan section 2) > var-non-minimal-zero (V3) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > var-five-bytes (Str1) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > var-four-continuation-truncated (V1) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > var-truncated (V1) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > var-max-length (Str1) gives lengthMismatch [0.04ms] +(pass) structured vectors (test-plan section 2) > count-metadata (C) gives lengthMismatch [0.04ms] +(pass) structured vectors (test-plan section 2) > count-planes (C) gives lengthMismatch [0.04ms] +(pass) structured vectors (test-plan section 2) > count-attributes (C) gives lengthMismatch [0.07ms] +(pass) structured vectors (test-plan section 2) > count-planes-edge-ok (C) gives ok [0.07ms] +(pass) structured vectors (test-plan section 2) > count-planes-over-pmax-and-remaining (C) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > str-remaining-plus-one (Str1) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > str-remaining-before-limit (Str1) gives lengthMismatch [0.09ms] +(pass) structured vectors (test-plan section 2) > str-two-byte-var-exact-ok (Str1) gives ok [0.08ms] +(pass) structured vectors (test-plan section 2) > str-two-byte-var-plus-one (Str1) gives lengthMismatch [0.05ms] +(pass) structured vectors (test-plan section 2) > str-over-record (Str2) gives oversizedRecord [0.04ms] +(pass) structured vectors (test-plan section 2) > str-preamble-over-r-minus-1 (S7) gives oversizedRecord [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-overlong (Str3) gives invalidUTF8 [0.26ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-surrogate (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-above-max (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-truncated (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-lone-continuation (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-scalar-ff (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-body-split (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > utf8-before-line-break (Str3) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > scalar-lf (Str4) gives invalidDocument [0.07ms] +(pass) structured vectors (test-plan section 2) > scalar-cr (Str4) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > flags-document-bit2 (S1) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > flags-document-bit7 (S1) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > flags-plane-bit7 (P1) gives invalidContainer [0.02ms] +(pass) structured vectors (test-plan section 2) > flags-plane-z-form-0 (P1) gives invalidContainer [0.02ms] +(pass) structured vectors (test-plan section 2) > number-f32-integer (N) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > number-f32-negative-zero (N) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > number-f32-nan (N) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > number-f32-infinity (N) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > number-f32-truncated (N) gives lengthMismatch [0.02ms] +(pass) structured vectors (test-plan section 2) > number-f64-truncated (N) gives lengthMismatch [0.02ms] +(pass) structured vectors (test-plan section 2) > number-f64-integer (N) gives invalidContainer [0.06ms] +(pass) structured vectors (test-plan section 2) > number-f64-binary32 (N) gives invalidContainer [0.05ms] +(pass) structured vectors (test-plan section 2) > number-f64-negative-zero (N) gives invalidContainer [0.04ms] +(pass) structured vectors (test-plan section 2) > number-f64-nan (N) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > number-f64-negative-infinity (N) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > number-f64-int-boundary (N) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > number-f32-two-pow-27-ok (N) gives ok [0.07ms] +(pass) structured vectors (test-plan section 2) > number-f64-two-pow-53-plus-2-ok (N) gives ok [0.05ms] +(pass) structured vectors (test-plan section 2) > number-f32-for-f64-value (N) gives ok [0.04ms] +(pass) structured vectors (test-plan section 2) > order-metadata-decreasing (S6) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > order-metadata-identical (S6) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > order-nfc-instead-of-bytes (S6) gives invalidContainer [0.03ms] +(pass) structured vectors (test-plan section 2) > order-utf16-instead-of-bytes (S6) gives invalidContainer [0.05ms] +(pass) structured vectors (test-plan section 2) > order-equivalent-keys (S6b) gives invalidDocument [0.10ms] +(pass) structured vectors (test-plan section 2) > order-equivalent-kelvin (S6b) gives invalidDocument [0.05ms] +(pass) structured vectors (test-plan section 2) > order-attributes-decreasing (P7) gives invalidContainer [0.04ms] +(pass) structured vectors (test-plan section 2) > order-attributes-equivalent (P7a) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > order-keys-ok (S6) gives ok [0.17ms] +(pass) structured vectors (test-plan section 2) > field-empty-version (S2) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > axis-uppercase (R2) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > axis-leading-space (R2) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > axis-trailing-tab (R2) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > axis-trailing-nbsp (R2) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > axis-non-ascii-uppercase (R2) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > axis-unicode-ok (R2) gives ok [0.04ms] +(pass) structured vectors (test-plan section 2) > metadata-key-colon (R3) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > metadata-key-hash (R3) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > metadata-key-leading-space (R3) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > metadata-key-trailing-ideographic-space (R3) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > metadata-key-axis (R3) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > metadata-key-title (R3) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > metadata-key-version (R3) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > metadata-key-empty-ok (R3) gives ok [0.04ms] +(pass) structured vectors (test-plan section 2) > attribute-key-empty (R9) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > attribute-key-uppercase (R9) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > attribute-key-label (R9) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > attribute-key-z (R9) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > attribute-key-equals (R9) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > attribute-key-space (R9) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > attribute-key-tab (R9) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > attribute-key-leading-nbsp (R9) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > attribute-key-sigma (R9) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > duplicate-z (L0) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > preamble-without-planes (S8) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > too-many-planes (S8) gives tooManyPlanes [0.03ms] +(pass) structured vectors (test-plan section 2) > segment-empty-preamble (G1) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > segment-trailing-cr (G2) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > segment-inner-cr-ok (G2) gives ok [0.06ms] +(pass) structured vectors (test-plan section 2) > segment-crlf (G3) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > segment-leading-blank (G4) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > segment-trailing-blank (G4) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > segment-leading-nbsp-line (G4) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > segment-trailing-ideographic-line (G4) gives invalidDocument [0.05ms] +(pass) structured vectors (test-plan section 2) > segment-plane-line (G5) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > segment-plane-directive (G5) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > segment-plane-tab (G5) gives invalidDocument [0.02ms] +(pass) structured vectors (test-plan section 2) > segment-indented-plane-ok (G5) gives ok [0.04ms] +(pass) structured vectors (test-plan section 2) > segment-planet-ok (G5) gives ok [0.05ms] +(pass) structured vectors (test-plan section 2) > segment-fence-backtick-tilde-ok (G5) gives ok [0.04ms] +(pass) structured vectors (test-plan section 2) > segment-fence-tilde-closed (G5) gives invalidDocument [0.22ms] +(pass) structured vectors (test-plan section 2) > segment-fence-nbsp-indented-ok (G5) gives ok [0.16ms] +(pass) structured vectors (test-plan section 2) > segment-fence-open-not-final (G6) gives invalidDocument [0.05ms] +(pass) structured vectors (test-plan section 2) > segment-fence-open-final-ok (G6) gives ok [0.09ms] +(pass) structured vectors (test-plan section 2) > segment-fence-open-preamble (G6) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > segment-bom-nul-ok (Str3) gives ok [0.06ms] +(pass) structured vectors (test-plan section 2) > phase-q-apostrophe (Q) gives invalidDocument [0.16ms] +(pass) structured vectors (test-plan section 2) > phase-q-double-quote (Q) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > phase-q-paired-ok (Q) gives ok [0.10ms] +(pass) structured vectors (test-plan section 2) > phase-q-spaced-pair-ok (Q) gives ok [0.24ms] +(pass) structured vectors (test-plan section 2) > phase-q-quoted-space-ok (Q) gives ok [0.22ms] +(pass) structured vectors (test-plan section 2) > phase-q-swallow-next (Q) gives invalidDocument [0.11ms] +(pass) structured vectors (test-plan section 2) > phase-q-inject-z (Q) gives invalidDocument [0.06ms] +(pass) structured vectors (test-plan section 2) > phase-q-inject-label (Q) gives invalidDocument [0.09ms] +(pass) structured vectors (test-plan section 2) > phase-q-uppercase-quoted (Q) gives invalidDocument [0.05ms] +(pass) structured vectors (test-plan section 2) > limit-record-below-3 (L1) gives oversizedRecord [0.04ms] +(pass) structured vectors (test-plan section 2) > limit-frontmatter-line (L2) gives oversizedRecord [0.03ms] +(pass) structured vectors (test-plan section 2) > limit-directive-line (L3) gives oversizedRecord [0.03ms] +(pass) structured vectors (test-plan section 2) > limit-text-length (L4) gives oversizedOutput [0.03ms] +(pass) structured vectors (test-plan section 2) > limit-lines (L5) gives tooManyLines [0.04ms] +(pass) structured vectors (test-plan section 2) > precedence-l0-over-l3 (L0) gives invalidDocument [0.03ms] +(pass) structured vectors (test-plan section 2) > precedence-l3-over-l4 (L3) gives oversizedRecord [0.03ms] +(pass) structured vectors (test-plan section 2) > precedence-l4-over-l5 (L4) gives oversizedOutput [0.03ms] +(pass) structured vectors (test-plan section 2) > precedence-s-order (S9) gives invalidDocument [0.04ms] +(pass) structured vectors (test-plan section 2) > precedence-utf8-before-limits (S4) gives invalidUTF8 [0.03ms] +(pass) structured vectors (test-plan section 2) > end-trailing-byte (S10) gives lengthMismatch [0.03ms] +(pass) structured vectors (test-plan section 2) > bound-2dmax-exact (L4) gives oversizedOutput [0.03ms] +(pass) structured vectors (test-plan section 2) > eighty-planes-emax-1000 (L4) gives ok [0.19ms] +(pass) structured vectors (test-plan section 2) > edges-maximumDecodedBytes-at (L4) gives ok [0.13ms] +(pass) structured vectors (test-plan section 2) > edges-maximumDecodedBytes-below (L4) gives oversizedOutput [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumLines-at (L5) gives ok [0.06ms] +(pass) structured vectors (test-plan section 2) > edges-maximumLines-below (L5) gives tooManyLines [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumPlanes-at (S8) gives ok [0.07ms] +(pass) structured vectors (test-plan section 2) > edges-maximumPlanes-below (S8) gives tooManyPlanes [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumRecordBytes-at (L3) gives ok [0.08ms] +(pass) structured vectors (test-plan section 2) > edges-maximumRecordBytes-below (L3) gives oversizedRecord [0.03ms] +(pass) structured vectors (test-plan section 2) > edges-maximumEncodedBytes-at (D2) gives ok [0.07ms] +(pass) structured vectors (test-plan section 2) > edges-maximumEncodedBytes-below (D2) gives oversizedInput [0.03ms] +(pass) structured vectors (test-plan section 2) > preamble-record-31 (Str2) gives ok [0.05ms] +(pass) structured vectors (test-plan section 2) > preamble-record-30 (Str2) gives oversizedRecord [0.02ms] +(pass) structured unit checklist (test-plan section 3) > Var encodes and decodes minimally at every byte-count boundary [17.20ms] +(pass) structured unit checklist (test-plan section 3) > Var rejections V1 to V3 [0.34ms] +(pass) structured unit checklist (test-plan section 3) > number forms follow SPEC.md 11.3.3 and every encoding decodes bit for bit [0.33ms] +(pass) structured unit checklist (test-plan section 3) > CRC check value, slicing against a bytewise reference, and container checksums [77.47ms] +(pass) structured unit checklist (test-plan section 3) > chunked UTF-8 validation agrees with whole-string validation at every chunk boundary [11.30ms] +(pass) structured unit checklist (test-plan section 3) > segment rules G1 to G6 on hand cases [0.43ms] +(pass) structured unit checklist (test-plan section 3) > segment scanner agrees with the 2.0 parser round trip on 100,000 random bodies [1376.81ms] +(pass) structured unit checklist (test-plan section 3) > canonical text metrics equal the 2.0 writer on every Example and 100,000 generated documents [8832.17ms] +(pass) structured unit checklist (test-plan section 3) > byte-order keys: code point order equals UTF-8 byte order, never UTF-16 order [80.31ms] +(pass) structured unit checklist (test-plan section 3) > key equivalence matches normalize("NFC") on decode [0.60ms] +(pass) structured unit checklist (test-plan section 3) > numeric-powers.json: 4,318 canonical spellings [12.72ms] +(pass) structured unit checklist (test-plan section 3) > containerInfo reports raw header fields without validating them [0.71ms] +(pass) structured unit checklist (test-plan section 3) > encodeTextContainer keeps the 2.0 binary writer's bytes and error order [11.32ms] +(pass) structured unit checklist (test-plan section 3) > writer edges: W1b, the exact Emax cap, compression after the self-check [0.65ms] +(pass) structured unit checklist (test-plan section 3) > TypeScript writer: lone surrogates, equivalent-key merge, dropped values and __proto__ [0.80ms] +(pass) structured unit checklist (test-plan section 3) > the portable utf8Length path, where String.prototype.isWellFormed is missing, writes the same bytes [5.25ms] +(pass) structured unit checklist (test-plan section 3) > decoded values have the 2.0 bounded decoder's shape [0.20ms] +(pass) structured unit checklist (test-plan section 3) > Unicode skew vectors outside Unicode 13.0 (recorded for the runtime's Unicode data) [1.74ms] +(pass) structured unit checklist (test-plan section 3) > size gate G6 (perf-gate section 4) holds for the Examples and the committed large-input sizes [82.82ms] +(pass) structured unit checklist (test-plan section 3) > the package index exports exactly the two new storage names [0.50ms] +(pass) TypeScript chunked decoding never carries bytes into the next string > Bun: a truncated last chunk and the following string both report invalidUTF8 [26.71ms] +(pass) TypeScript chunked decoding never carries bytes into the next string > Node: the same two-call sequences on the current sources [121.35ms] +(pass) differential properties at CI volume (test-plan section 4) > P1, P2 and P3 over 10,410 mutants of every anchor and the kind-2 Examples (seed 0x51a7) [2212.40ms] +(pass) differential properties at CI volume (test-plan section 4) > P5: encode(D, L) succeeds exactly when decode(encode(D, L), L) does, and returns the normalized D [97.00ms] +(pass) differential properties at CI volume (test-plan section 4) > P6: binary acceptance equals validate under standard and lowered limits, and decode equals the text decode [743.09ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > before entry: a pre-aborted signal fails every storage entry point with its reason [0.19ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > every decode and encode check point aborts with the reason and leaves no partial result [30.90ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > mid-CRC on a 64 MiB input [301.12ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > inside a 1 MiB scalar scan and between the UTF-8 chunks of an 8 MiB body [181.96ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > before plane k of 65,536 and in Phase L [809.00ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > before and after a Phase Q parse [0.59ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > mid-emission and mid-self-check on encode [1.05ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > the result walk checks by bytes inside one plane of 700,000 attributes (standard limits) [1260.83ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > the equivalence checks of long decomposed keys check by bytes, metadata and attributes (standard limits) [562.59ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > the writer checks by work inside large maps: merge tests, sorts, the plan and the emission [1659.27ms] +Bun memory growth / input: body a: 2.58, body é: 2.55, body €: 2.26, body 😀: 2.53, planes: 2.14, attributes: 1.23 +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > memory on Bun: resident growth under 4 times the input for the 64 MiB worst cases and an 8 MiB body [2283.74ms] +Node memory growth / input: body a: 2.11, body é: 2.10, body €: 1.75, body 😀: 2.12, planes: 2.86, attributes: 1.04 +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > memory on Node: the same cases on the current sources [2157.61ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > amplification: 65,536 quoted-key planes over R are rejected before any Phase Q parse, in under a second [259.52ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > Phase S allocates nothing per key: 2,000,000 minimal attributes stay far below 4 times the input [795.86ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > buffer ownership: overwriting or slicing the caller's buffer never changes a decoded value [2.23ms] +(pass) cancellation, resource bounds and buffer ownership (test-plan section 5) > a kind-2 file whose uncompressed container exceeds Emax or 2 Dmax stops at D10 before the CRC [0.20ms] + +test/composition.test.ts: +(pass) bounded self-contained composition > safe ID grammar, duplicates, absent roots and unreachable missing targets fail [1.95ms] +(pass) bounded self-contained composition > cycles, unused cycles, cached depth and repeated-traversal occurrence limits fail [1.00ms] +(pass) bounded self-contained composition > counts, unique source bytes and per-reference UTF-8 attributes are bounded [0.34ms] +(pass) bounded self-contained composition > constructors enforce absolute integer limits and legitimate zero reference limits [0.07ms] +(pass) bounded self-contained composition > public graph codecs validate plain-object composition policies before reading or writing [0.16ms] +(pass) bounded self-contained composition > strict envelopes, schemas, unknown fields and JSON types are rejected [0.87ms] +(pass) bounded self-contained composition > duplicate escaped keys, nested records, numeric fields and trailing JSON fail before object decoding [0.58ms] +(pass) bounded self-contained composition > embedded paths and malformed unused sources stay local parse errors [0.30ms] +(pass) bounded self-contained composition > profile and escaped JSON bounds count the complete envelope [0.40ms] +(pass) bounded self-contained composition > opaque attributes preserve controls, Unicode and prototype-looking keys [0.40ms] +(pass) bounded self-contained composition > pre-aborted graph construction and codecs propagate cancellation [0.12ms] +(pass) bounded self-contained composition > new reference writers sort Unicode scalar keys and strict JSON rejects equivalent duplicate keys [1.43ms] + +test/conformance.test.ts: +(pass) conformance vectors > at least one valid and one invalid vector exist [0.26ms] +(pass) conformance vectors > invalid-duplicate-plane.json: two planes sharing the same z value are rejected [0.14ms] +(pass) conformance vectors > invalid-duplicate-z-decimal-forms.json: z=0 and z=0.0 are the same position [0.03ms] +(pass) conformance vectors > invalid-frontmatter-no-colon.json: frontmatter line without a colon separator is rejected [0.03ms] +(pass) conformance vectors > invalid-frontmatter-unclosed.json: frontmatter block that is never closed is rejected [0.02ms] +(pass) conformance vectors > invalid-missing-frontmatter.json: document without a frontmatter fence is rejected +(pass) conformance vectors > invalid-missing-plane-position.json: a plane directive with no z attribute is rejected [0.02ms] +(pass) conformance vectors > invalid-missing-version.json: frontmatter without the 3md version key is rejected +(pass) conformance vectors > invalid-plane-token-no-equals.json: a plane attribute token with no equals sign is rejected (Swift throws; it is not skipped) [0.04ms] +(pass) conformance vectors > invalid-plane-x-not-number.json: a plane directive whose x is not a number is rejected [0.03ms] +(pass) conformance vectors > invalid-plane-z-not-number.json: a plane directive whose z is not a number is rejected [0.02ms] +(pass) conformance vectors > invalid-unterminated-quote.json: an unterminated quote in a directive is rejected [0.01ms] +(pass) conformance vectors > invalid-z-hex.json: hex z is rejected so Swift and TS agree +(pass) conformance vectors > invalid-z-infinity.json: z=inf is rejected (non-finite) +(pass) conformance vectors > invalid-z-nan.json: z=nan is rejected (non-finite, also closes the NaN dedup bypass) +(pass) conformance vectors > invalid-z-thousands-separator.json: thousands separators are rejected +(pass) conformance vectors > links-basic.json: a [[z=N]] reference resolves to the source z, target z, and existence [0.11ms] +(pass) conformance vectors > links-dangling.json: a reference to a missing plane is reported with targetExists false [0.01ms] +(pass) conformance vectors > links-decimal-target.json: a decimal target z is matched against a decimal plane z [0.01ms] +(pass) conformance vectors > links-invalid-ignored.json: non-finite targets and ordinary Markdown links are not cross-plane links +(pass) conformance vectors > links-multiple.json: multiple links in one body are returned left to right [0.01ms] +(pass) conformance vectors > links-with-text.json: a [[z=N|text]] reference captures the link text [0.01ms] +(pass) conformance vectors > valid-attribute-numeric-stays-string.json: non z/x/y attributes stay strings, not coerced [0.04ms] +(pass) conformance vectors > valid-axis-default.json: axis defaults to layer when omitted +(pass) conformance vectors > valid-axis-lowercased.json: axis value is trimmed and lowercased +(pass) conformance vectors > valid-bom.json: a leading UTF-8 BOM is stripped before parsing +(pass) conformance vectors > valid-code-block-directive-safe.json: a @plane line inside a fenced code block stays body text +(pass) conformance vectors > valid-coordinates-attributes.json: coordinates, label, and extra attributes are captured [0.02ms] +(pass) conformance vectors > valid-crlf.json: CRLF line endings are normalized to LF [0.01ms] +(pass) conformance vectors > valid-decimal-negative-z.json: z accepts negative and decimal values and keeps source order +(pass) conformance vectors > valid-empty-body.json: frontmatter only with no body yields no planes +(pass) conformance vectors > valid-empty-plane-body.json: a plane directive with no following content has an empty body +(pass) conformance vectors > valid-escaped-quote-label.json: escaped quotes inside a quoted label round-trip +(pass) conformance vectors > valid-frontmatter-comments.json: frontmatter skips comment and blank lines and strips quotes +(pass) conformance vectors > valid-indented-directive-is-body.json: an indented @plane is body, not a directive +(pass) conformance vectors > valid-leading-blank-lines.json: leading blank lines before the frontmatter fence are allowed +(pass) conformance vectors > valid-metadata-key-case-preserved.json: non-reserved frontmatter keys keep their case [0.01ms] +(pass) conformance vectors > valid-multi-plane.json: valid multi-plane document with title, metadata, and preamble [0.02ms] +(pass) conformance vectors > valid-plane-prefix-not-directive.json: @planex is not a directive; the doc is single-plane shorthand +(pass) conformance vectors > valid-preamble-with-planes.json: preamble is preserved when planes follow and quoted attribute keeps spaces [0.09ms] +(pass) conformance vectors > valid-repeated-directive-key-last-wins.json: a repeated directive key takes the last value [0.02ms] +(pass) conformance vectors > valid-single-plane-shorthand.json: single-plane shorthand wraps body at z=0 when no directives +(pass) conformance vectors > valid-version-1-0.json: the 1.0 format marker parses, with version reported as 1.0 +(pass) conformance vectors > valid-z-scientific-notation.json: scientific notation in z parses as a decimal [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-attribute-numeric-stays-string.json: non z/x/y attributes stay strings, not coerced [0.11ms] +(pass) round trip: parse -> serialize -> parse > valid-axis-default.json: axis defaults to layer when omitted [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-axis-lowercased.json: axis value is trimmed and lowercased [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-bom.json: a leading UTF-8 BOM is stripped before parsing [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-code-block-directive-safe.json: a @plane line inside a fenced code block stays body text [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-coordinates-attributes.json: coordinates, label, and extra attributes are captured [0.05ms] +(pass) round trip: parse -> serialize -> parse > valid-crlf.json: CRLF line endings are normalized to LF [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-decimal-negative-z.json: z accepts negative and decimal values and keeps source order [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-empty-body.json: frontmatter only with no body yields no planes [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-empty-plane-body.json: a plane directive with no following content has an empty body [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-escaped-quote-label.json: escaped quotes inside a quoted label round-trip [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-frontmatter-comments.json: frontmatter skips comment and blank lines and strips quotes [0.03ms] +(pass) round trip: parse -> serialize -> parse > valid-indented-directive-is-body.json: an indented @plane is body, not a directive [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-leading-blank-lines.json: leading blank lines before the frontmatter fence are allowed [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-metadata-key-case-preserved.json: non-reserved frontmatter keys keep their case [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-multi-plane.json: valid multi-plane document with title, metadata, and preamble [0.04ms] +(pass) round trip: parse -> serialize -> parse > valid-plane-prefix-not-directive.json: @planex is not a directive; the doc is single-plane shorthand +(pass) round trip: parse -> serialize -> parse > valid-preamble-with-planes.json: preamble is preserved when planes follow and quoted attribute keeps spaces [0.03ms] +(pass) round trip: parse -> serialize -> parse > valid-repeated-directive-key-last-wins.json: a repeated directive key takes the last value [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-single-plane-shorthand.json: single-plane shorthand wraps body at z=0 when no directives [0.01ms] +(pass) round trip: parse -> serialize -> parse > valid-version-1-0.json: the 1.0 format marker parses, with version reported as 1.0 [0.02ms] +(pass) round trip: parse -> serialize -> parse > valid-z-scientific-notation.json: scientific notation in z parses as a decimal [0.02ms] + +test/editing.test.ts: +(pass) portable atomic editing and diagnostics > adoption skips existing IDs, preserves id metadata and rejects unsafe or duplicated identities [0.80ms] +(pass) portable atomic editing and diagnostics > snapshots deep-copy and freeze values; reconstruction rejects a forged revision [0.77ms] +(pass) portable atomic editing and diagnostics > insert, move, remove and header replacements are one pure transaction [0.49ms] +(pass) portable atomic editing and diagnostics > later invalid operation rolls back; replacement identities, indices and missing targets are precise [0.51ms] +(pass) portable atomic editing and diagnostics > exact revisions reject NFC-equivalent bytes and expected-content budgets [0.32ms] +(pass) portable atomic editing and diagnostics > structurally typed snapshot revisions cannot replace the exact-content comparison [0.60ms] +(pass) portable atomic editing and diagnostics > operation, payload and final invalid-document policies return no partial result [0.34ms] +(pass) portable atomic editing and diagnostics > two NaN coordinate replacements reach invalid-document validation without a false duplicate [0.12ms] +(pass) portable atomic editing and diagnostics > graph patches allow forward definitions and final root swaps without flattening [1.61ms] +(pass) portable atomic editing and diagnostics > graph final failures identify the missing target or root and enforce scoped IDs [1.95ms] +(pass) portable atomic editing and diagnostics > source diagnostics carry only actual parser lines; value paths and truncation stay precise [0.55ms] +(pass) portable atomic editing and diagnostics > diagnostic payload preflight precedes expensive graph validation and retains owner paths [2.31ms] +(pass) portable atomic editing and diagnostics > all identity, transaction and diagnostic entry points honor pre-aborted signals [0.39ms] +(pass) portable atomic editing and diagnostics > public editor and diagnostic boundaries reject forged plain-object policies [0.30ms] + +test/storage.test.ts: +(pass) bounded portable storage > fixed envelope vectors match Swift and sliced data retains its byte offset [0.20ms] +(pass) bounded portable storage > existing Swift canopy and grove envelopes remain readable and byte-identical [2.05ms] +(pass) bounded portable storage > LZFSE is explicitly unavailable while unknown compression remains a different error [0.20ms] +(pass) bounded portable storage > header fields, checksums, trailing bytes and unsafe 64-bit lengths are checked [0.27ms] +(pass) bounded portable storage > the same header, checksum and payload checks hold for payload kind 2 [0.17ms] +(pass) bounded portable storage > resource constructors reject noninteger and nonpositive limits and accept any safe size [0.08ms] +(pass) bounded portable storage > a document past the old 64 MiB ceiling round-trips as text and as kind 2 [1563.62ms] +(pass) bounded portable storage > public storage boundaries validate structurally typed plain-object policies [0.25ms] +(pass) bounded portable storage > exact byte boundaries succeed; physical lines, planes and entire records are bounded [0.41ms] +(pass) bounded portable storage > preflight respects code fences and preserves the existing parser/serializer behavior [0.12ms] +(pass) bounded portable storage > direct lossy values and malformed decimals fail without changing legacy text APIs [2.76ms] +(pass) bounded portable storage > hostile interior and trailing ASCII whitespace remains exact through text and portable storage [23.68ms] +(pass) bounded portable storage > pre-aborted operations propagate the abort reason [0.22ms] +(pass) bounded portable storage > new canonical maps use Swift Unicode key equality, scalar order and original spelling [0.68ms] + +test/interchange-adapter.test.ts: +(pass) development files adapter limits > limit literals are judged by their correctly rounded IEEE double, like Swift and Rust [94.47ms] + +test/extensions.test.ts: +(pass) Swift portable extension conformance > all IEEE754 number vectors match Swift canonical formatting [0.94ms] +(pass) Swift portable extension conformance > Swift scientific notation starts strictly above the exact 2^53 boundary [0.03ms] +(pass) Swift portable extension conformance > canonical Unicode document text, envelope and revision are byte-identical to Swift [0.79ms] +(pass) Swift portable extension conformance > canonical composition preserves shared definitions, instance IDs and exact profile bytes [1.98ms] +(pass) Swift portable extension conformance > additive Swift Unicode key ordering and source-collision goldens match the portable codecs [1.51ms] +(pass) Swift portable extension conformance > identity adoption follows the Swift fixture and preserves ordinary id metadata [0.89ms] +(pass) Swift portable extension conformance > document transaction: atomic-coordinate-swap [0.49ms] +(pass) Swift portable extension conformance > document transaction: source-order-change [0.31ms] +(pass) Swift portable extension conformance > composition transaction: retarget-and-reorder-owner-instance [1.37ms] +(pass) Swift portable extension conformance > composition transaction: remove-one-repeated-target-instance [1.16ms] +(pass) Swift portable extension conformance > atomic failure: stale-document-revision [0.32ms] +(pass) Swift portable extension conformance > atomic failure: final-coordinate-conflict [0.14ms] +(pass) Swift portable extension conformance > atomic failure: changed-plane-identity [0.12ms] +(pass) Swift portable extension conformance > atomic failure: stale-composition-revision [0.05ms] +(pass) Swift portable extension conformance > atomic failure: final-reference-cycle [0.46ms] +(pass) Swift portable extension conformance > atomic failure: wrong-owner-reference-target [0.34ms] + +test/file-composition.test.ts: +(pass) explicit supplied-file composition > simple and repeated glyph links deduplicate files and refresh changed child bytes [1.47ms] +(pass) explicit supplied-file composition > nested parent paths and duplicate basenames resolve relative to each containing file [1.06ms] +(pass) explicit supplied-file composition > payload kind 1 children and bundles (the 2.0 binary bytes) still resolve [1.26ms] +(pass) explicit supplied-file composition > binary nested bundles retain unused entries, stable identities and opaque edges before new ledger edges [1.65ms] +(pass) explicit supplied-file composition > nested profile records use the outer composition policy while embedded ordinary records retain child bounds [1499.82ms] +(pass) explicit supplied-file composition > paths use NFC and Unicode scalar ordering rather than UTF16 or locale sorting [1.17ms] +(pass) explicit supplied-file composition > path grammar rejects escape, absolute paths, empty segments, controls and normalized aliases [0.58ms] +(pass) explicit supplied-file composition > strict ledger scanner rejects duplicate escaped keys, malformed JSON and invalid glyphs before values [0.43ms] +(pass) explicit supplied-file composition > missing files and malformed reachable storage retain distinct errors, unreachable storage is ignored [0.35ms] +(pass) explicit supplied-file composition > file cycles also fail when unused bundle entries form a cycle across files [0.88ms] +(pass) explicit supplied-file composition > supplied counts, original path bytes and reachable bytes use input limits before decoding [105.72ms] +(pass) explicit supplied-file composition > outer recognition applies child byte and line policies before its lowered plane ceiling [1.01ms] +(pass) explicit supplied-file composition > disconnected embedded ledgers use final entry depth rather than incoming file depth [0.93ms] +(pass) explicit supplied-file composition > repeated cached dependencies validate final depth after complete discovery [0.79ms] +(pass) explicit supplied-file composition > independent fixed64 discovery safety bounds disconnected file chains [35.29ms] +(pass) explicit supplied-file composition > lowered policies enforce final graph depth, imported entries, edges, conceptual traversal and final profile size [0.96ms] +(pass) explicit supplied-file composition > pre-aborted and cooperatively aborted operations propagate the caller's cancellation reason [0.16ms] +(pass) linked composition parity hardening > static resolve, ledger and resolvePath do not depend on their class binding [0.26ms] +(pass) linked composition parity hardening > owner directories keep parent, dot and grammar semantics [0.11ms] +(pass) linked composition parity hardening > a long owner path with many references resolves every reference in its directory [7.58ms] +(pass) linked composition parity hardening > refusals follow entry ID, then glyph, discovery order [1.03ms] +(pass) linked composition parity hardening > root and unreachable supplied paths use the ledger path grammar [0.73ms] +(pass) linked composition parity hardening > ledger escapes decode before path grammar [0.74ms] +(pass) linked composition parity hardening > self and alias cycles compare normalized paths [0.35ms] +(pass) linked composition parity hardening > a cached subtree is charged at its deeper occurrence against the discovery ceiling [41.05ms] +(pass) linked composition parity hardening > existing edges precede ledger edges; embedded ledgers resolve from their bundle folder; output rebundles [1.96ms] +(pass) linked composition parity hardening > the source-file attribute bound counts normalized UTF-8 bytes [10.47ms] +(pass) linked composition parity hardening > lowered policies charge original path bytes before path grammar; invalid limits are refused first [0.19ms] +(pass) linked composition parity hardening > an abort inside the ledger scanner propagates the caller's reason [1.91ms] +(pass) linked composition parity hardening > an abort inside the scalar path sort propagates the caller's reason [1.69ms] +(pass) early source-file attribute bound and long-directory owners > an over-bound ledger edge is refused while resolving, before later refusals [0.39ms] +(pass) early source-file attribute bound and long-directory owners > the attribute bound counts normalized directory prefix bytes [0.45ms] +(pass) early source-file attribute bound and long-directory owners > long-directory owners resolve repeated sources once and refuse over-bound targets at the first edge [189.50ms] + +test/links.test.ts: +(pass) links() > basic reference resolves source, target, and existence [0.85ms] +(pass) links() > captures optional link text [0.04ms] +(pass) links() > present-but-empty link text is the empty string [0.02ms] +(pass) links() > multiple links in one body are returned left to right [0.02ms] +(pass) links() > links across planes follow source order [0.02ms] +(pass) links() > dangling reference reports targetExists false [0.02ms] +(pass) links() > decimal target matches a decimal plane z [0.02ms] +(pass) links() > non-finite and non-link sequences are ignored [0.01ms] +(pass) links() > signed and exponent targets parse as finite decimals [0.02ms] +(pass) links() > a document with no links returns an empty array [0.01ms] +(pass) links() > danglingLinks filters only missing targets [0.05ms] +(pass) links() > linkGraph collapses repeated source-target pairs [0.10ms] +(pass) links() > linkGraph keeps dangling edge status [0.03ms] + + 431 pass + 0 fail + 764396 expect() calls +Ran 431 tests across 10 files. [27.81s] + ✔ Step 4 done (29.778s) + ▶️ Running task: rust + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.16s + Finished `test` profile [unoptimized + debuginfo] target(s) in 0.08s + Running unittests src/lib.rs (target/debug/deps/threemd-3e8d3a72ef8b0b84) + +running 18 tests +test checksum::tests::check_value_matches_the_specification ... ok +test structured::tests::number_forms_follow_the_table_and_decode_bit_exactly ... ok +test structured::tests::var_round_trips_at_every_size_boundary_and_rejects_v1_to_v3 ... ok +test structured::tests::equivalence_is_rejected_only_for_canonically_equal_distinct_keys ... ok +test structured::tests::line_feed_bits_mark_exactly_the_line_feeds ... ok +test structured::tests::checked_chars_stop_at_a_failed_check_and_keep_the_error ... ok +test structured::tests::long_key_hashes_and_nfc_forms_check_cancellation_on_their_input ... ok +test structured::tests::every_cancellation_check_cancels_decode_and_encode_without_a_result ... ok +test structured::tests::phase_s_checks_cancellation_within_long_keys_and_axes ... ok +test checksum::tests::slicing_matches_the_bytewise_reference_at_every_alignment ... ok +test structured::tests::cancellation_reaches_long_scans_and_every_plane ... ok +test structured::tests::lowercase_test_agrees_with_to_lowercase ... ok +test structured::tests::w2_checks_cancellation_between_short_keys_and_within_long_keys ... ok +test structured::tests::phase_q_normalizes_each_key_once_in_the_2_0_writer_order ... ok +test structured::tests::equivalence_matches_brute_force_and_compares_forms_only_when_hashes_meet ... ok +test structured::tests::cancellation_reaches_the_crc_of_a_64_mib_input ... ok +test structured::tests::phase_q_runs_only_after_phase_l_bounds_every_directive ... ok +test structured::tests::long_key_nfc_test_agrees_with_is_nfc_and_checks_every_chunk ... ok + +test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.50s + + Running tests/conformance.rs (target/debug/deps/conformance-283cd1b2cb105be9) + +running 1 test +test conformance_vectors_pass ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s + + Running tests/editing.rs (target/debug/deps/editing-997e6fa6b85c2c5a) + +running 9 tests +test direct_btree_maps_reject_ambiguous_canonically_equivalent_keys ... ok +test operation_payload_and_final_document_policies_are_enforced ... ok +test adopted_entries_report_the_specific_graph_error_that_adoption_wraps ... ok +test all_document_operations_preserve_source_order_and_header_fields ... ok +test identity_adoption_is_explicit_and_scoped ... ok +test document_operation_failures_are_structured_and_do_not_mutate_input ... ok +test graph_revision_roundtrip_diagnostics_and_cancellation ... ok +test all_composition_operations_validate_the_final_graph_atomically ... ok +test graph_failures_validate_counts_identity_and_reference_existence ... ok + +test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s + + Running tests/extensions.rs (target/debug/deps/extensions-4eb0504670bb68cf) + +running 15 tests +test binary_header_fields_and_corruption_are_rejected ... ok +test bounded_diagnostics_preserve_real_parser_lines_and_legacy_ids ... ok +test canonical_decimal_ties_use_nearest_even_shortest_spelling ... ok +test exact_utf8_revision_reopen_and_forged_snapshot_validation ... ok +test storage_resource_policies_and_faithful_value_validation ... ok +test graph_validates_unused_entries_cycles_and_resource_limits ... ok +test swift_unicode_key_order_and_source_collision_semantics_match ... ok +test original_extension_artifacts_and_lzfse_unavailability ... ok +test composition_json_is_strict_and_rejects_decoded_duplicate_keys ... ok +test cancellation_propagates_without_publishing_values ... ok +test swift_numeric_vectors_match_exact_storage_spelling ... ok +test swift_document_and_composition_goldens_are_byte_identical ... ok +test swift_adoption_transactions_and_failures_match_semantics ... ok +test every_signed_power_of_two_and_ten_matches_the_shared_canonical_spelling ... ok +test a_document_past_the_old_ceiling_round_trips ... ok + +test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.19s + + Running tests/file_composition.rs (target/debug/deps/file_composition-82fdc3545091eafc) + +running 30 tests +test owner_directory_resolution_keeps_parent_dot_and_grammar_semantics ... ok +test outer_recognition_preserves_child_byte_and_line_policy_precedence_over_planes ... ok +test ledger_is_strict_json_with_ascii_glyph_validation_before_duplicate_checks ... ok +test attribute_bound_counts_normalized_directory_prefix_bytes ... ok +test outer_profile_records_are_independent_of_child_record_policy ... ok +test over_bound_ledger_edge_is_refused_while_resolving_before_later_refusals ... ok +test existing_edges_precede_ledger_edges_and_embedded_ledgers_resolve_from_their_bundle_folder ... ok +test lowered_policy_charges_original_path_bytes_before_grammar_and_rejects_invalid_limits_first ... ok +test nested_relative_paths_keep_duplicate_basenames_and_use_scalar_order ... ok +test disconnected_embedded_ledgers_use_actual_entry_depth_and_repeated_cached_files ... ok +test final_depth_checks_include_cached_dependencies_and_cancelled_operations_are_atomic ... ok +test missing_files_and_file_cycles_include_ledgers_in_unused_bundle_entries ... ok +test supplied_and_resolved_policies_are_checked_before_returning_a_bundle ... ok +test self_and_alias_cycles_compare_normalized_paths ... ok +test repeated_links_are_deterministic_and_preserve_the_ordinary_document ... ok +test ledger_escapes_decode_before_path_grammar ... ok +test unreachable_content_is_ignored_but_every_supplied_path_is_validated ... ok +test refusals_follow_entry_id_then_glyph_discovery_order ... ok +test root_and_unreachable_supplied_paths_use_the_ledger_path_grammar ... ok +test resolver_output_rebundles_with_opaque_glyph_and_source_file_attributes ... ok +test repeated_cached_files_validate_final_depth_and_missing_discovery_precedence ... ok +test binary_children_and_nested_bundles_preserve_unused_entries_and_reference_ids ... ok +test source_file_attribute_bound_counts_normalized_utf8_bytes ... ok +test discovery_ceiling_is_the_standard_maximum_depth ... ok +test fixed_file_discovery_ceiling_bounds_disconnected_chains ... ok +test cached_subtree_is_charged_at_its_deeper_occurrence_against_the_discovery_ceiling ... ok +test long_owner_path_with_many_references_resolves_every_reference_in_its_directory ... ok +test long_directory_owners_resolve_repeated_sources_once_and_refuse_over_bound_targets_early ... ok +test project_paths_have_explicit_rules_and_bounded_standalone_work ... ok +test cancellation_from_another_thread_during_resolution_returns_no_result ... ok + +test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.65s + + Running tests/interchange.rs (target/debug/deps/interchange-1ce7f8e1fb0daa3c) + +running 5 tests +test bounded_parse_keeps_limits_and_explicit_cancellation ... ok +test source_unicode_aliases_keep_first_spelling_and_last_value_in_both_parsers ... ok +test legacy_serializer_preserves_quoted_apostrophes_and_boundary_whitespace ... ok +test raw_and_bounded_parsers_share_foundation_horizontal_whitespace ... ok +test large_unique_plane_sets_and_numeric_duplicate_equality_are_preserved ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.45s + + Running tests/structured.rs (target/debug/deps/structured-e12e8226d3e976db) + +running 24 tests +test p1_to_p4_every_mutant_reports_the_shared_outcome ... ignored, 102,600 decodes; run with --release -- --ignored +test container_info_reports_raw_fields_without_validation ... ok +test unicode_skew_vectors_follow_this_toolchains_data ... ok +test payload_kind_dispatch_and_the_decoded_length_bound ... ok +test a_truncated_tail_never_carries_into_the_next_string_or_call ... ok +test worked_examples_have_the_specified_bytes ... ok +test writer_cap_negative_zero_and_compression_follow_w1_to_w6 ... ok +test compositions_accept_kind_1_and_2_envelopes_and_refuse_kind_3 ... ok +test text_container_writer_keeps_the_2_0_bytes_and_error_order ... ok +test every_vector_reports_its_code_under_its_limits ... ok +test new_types_are_send_and_sync_and_codecs_run_from_32_threads ... ok +test var_prefixes_at_size_boundaries_round_trip_through_bodies ... ok +test every_golden_is_reproduced_byte_for_byte_and_decodes_to_the_text_decode ... ok +test number_forms_round_trip_bit_exactly_and_spell_canonically ... ok +test g6_kind_2_sizes_match_sizes_json ... ok +test keys_are_written_in_byte_order_and_equivalent_spellings_are_rejected ... ok +test chunked_utf8_validation_agrees_with_whole_string_validation ... ok +test cancellation_returns_no_value_and_leaves_inputs_reusable ... ok +test p5_p6_writer_acceptance_equals_validate_under_standard_limits ... ok +test p5_p6_writer_acceptance_equals_validate_under_lowered_limits ... ok +test metrics_equal_the_canonical_text_on_every_example ... ok +test p1_to_p4_mutants_report_the_shared_outcomes ... ok +test segment_rules_agree_with_the_text_round_trip_on_random_bodies ... ok +test metrics_equal_the_canonical_text_on_generated_documents ... ok + +test result: ok. 23 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 6.74s + + Running tests/structured_memory.rs (target/debug/deps/structured_memory-4f6ad24055334ee6) + +running 1 test +test kind_2_decoding_stays_under_four_times_the_input ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 9.36s + + Running unittests examples/interchange.rs (target/debug/examples/interchange-3e1831aec2fdc659) + +running 9 tests +test tests::hex_is_exact_and_rejects_uppercase_or_odd_input ... ok +test tests::document_adapter_edits_and_rejects_stale_patch_for_both_file_formats ... ok +test tests::malformed_protocol_keys_numbers_and_depth_precede_source_count ... ok +test tests::supplied_file_adapter_rejects_malformed_protocol_and_maps_core_errors ... ok +test tests::supplied_file_adapter_emits_reopenable_composition_outputs ... ok +test tests::composition_adapter_preserves_references_and_binary_parity ... ok +test tests::file_limits_are_strict_shapes_with_library_validated_values ... ok +test tests::supplied_file_count_precedes_source_shape_validation_but_not_top_level_validation ... ok +test tests::oversized_requests_are_consumed_and_responses_are_atomic ... ok + +test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.10s + + Finished `test` profile [unoptimized + debuginfo] target(s) in 0.02s + Doc-tests threemd + +running 4 tests +test src/storage.rs - storage::DocumentContainerInfo (line 216) ... ok +test src/lib.rs - axis (line 67) ... ok +test src/lib.rs - ParseError::code (line 178) ... ok +test src/lib.rs - (line 12) ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.47s + + Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s + ✔ Step 5 done (34.550s) + ▶️ Running task: interchange +[0/1] Planning build +Building for debugging... +[0/3] Write swift-version--58304C5D6DBC2206.txt +Build of product 'threemd-interchange' complete! (0.24s) +{"cases":569,"compression":"none; optional Apple LZFSE excluded","imports":17991,"pairCounts":{"Rust -> Rust":1999,"Rust -> Swift":1999,"Rust -> TypeScript-Node":1999,"Swift -> Rust":1999,"Swift -> Swift":1999,"Swift -> TypeScript-Node":1999,"TypeScript-Node -> Rust":1999,"TypeScript-Node -> Swift":1999,"TypeScript-Node -> TypeScript-Node":1999},"passed":true,"producerConsumerPairs":9,"schema":"3md-interchange-receipt-1"} +Interchange evidence: /var/folders/5k/616qy7sj28l0d53k4c6w_4x00000gn/T/3md-interchange-1821610F-1D1B-407E-9F78-29D88EC6380A + ✔ Step 6 done (50.574s) + ▶️ Running task: element-bundle +Bundled 10 modules in 8ms + + three-md.js 48.84 KB (entry point) + +element bundle is current (48840 bytes, no storage code) + ✔ Step 7 done (46ms) + ▶️ Running task: editor +bun install v1.4.0 (34cbb9a40) + +Checked 183 installs across 192 packages (no changes) [47.00ms] +$ vscode-tmgrammar-test -g syntaxes/3md.tmLanguage.json -g syntaxes/3md-links.injection.json -g tests/grammars/markdown.tmLanguage.json "tests/*.3md" +grammar not found for "source.yaml" +grammar not found for "text.html.derivative" +grammar not found for "source.css" +grammar not found for "text.html.basic" +grammar not found for "source.ini" +grammar not found for "source.java" +grammar not found for "source.lua" +grammar not found for "source.makefile" +grammar not found for "source.perl" +grammar not found for "source.r" +grammar not found for "source.ruby" +grammar not found for "source.php" +grammar not found for "source.sql" +grammar not found for "source.asp.vb.net" +grammar not found for "text.xml" +grammar not found for "text.xml.xsl" +grammar not found for "source.batchfile" +grammar not found for "source.clojure" +grammar not found for "source.coffee" +grammar not found for "source.c" +grammar not found for "source.cpp" +grammar not found for "source.diff" +grammar not found for "source.dockerfile" +grammar not found for "text.git-commit" +grammar not found for "text.git-rebase" +grammar not found for "source.go" +grammar not found for "source.groovy" +grammar not found for "text.pug" +grammar not found for "source.ignore" +grammar not found for "source.js" +grammar not found for "source.js.regexp" +grammar not found for "source.json" +grammar not found for "source.json.comments" +grammar not found for "source.json.lines" +grammar not found for "source.css.less" +grammar not found for "source.objc" +grammar not found for "source.swift" +grammar not found for "source.css.scss" +grammar not found for "source.perl.6" +grammar not found for "source.powershell" +grammar not found for "source.python" +grammar not found for "source.julia" +grammar not found for "source.regexp.python" +grammar not found for "source.rust" +grammar not found for "source.scala" +grammar not found for "source.shell" +grammar not found for "source.ts" +grammar not found for "source.tsx" +grammar not found for "source.cs" +grammar not found for "source.fsharp" +grammar not found for "source.dart" +grammar not found for "text.html.handlebars" +grammar not found for "text.log" +grammar not found for "source.erlang" +grammar not found for "source.elixir" +grammar not found for "text.tex.latex" +grammar not found for "text.bibtex" +grammar not found for "source.twig" +grammar not found for "source.yang" +grammar not found for "source.abap" +grammar not found for "source.rst" +✓ tests/cross-plane-link.3md run successfuly. +✓ tests/frontmatter.3md run successfuly. +✓ tests/markdown-body.3md run successfuly. +✓ tests/plane-directive.3md run successfuly. + ✔ Step 8 done (539ms) +✅ Lane verify completed (8 steps in 3m 25.668s) +⊘ Skipped 4 unchanged spec(s) (use --force/--no-cache to re-validate all) + ℹ Cache: /Users/leif/Development/_CorvidLabs/3md-edit-preview/.specsync/hashes.json + +All specs unchanged — nothing to validate. +File coverage: 55/55 (100%) +LOC coverage: 21185/21185 (100%) +augur: config: loaded ./.augur.toml +augur gate · review (risk 36) +trust range: origin/leif/viewer-draft-navigation..HEAD +== lifecycle == +== contract == +== risk == +== provenance == +provenance degraded: policy is not satisfied +== atlas: off (Atlas publication was not enabled during adoption) == +trust gate passed (progressive provenance) diff --git a/specs/ThreeMDViewer/testing.md b/specs/ThreeMDViewer/testing.md index 3bc142c..62b0d23 100644 --- a/specs/ThreeMDViewer/testing.md +++ b/specs/ThreeMDViewer/testing.md @@ -76,3 +76,5 @@ Both current approved changes were successfully finalized and archived on 2026-1 At 1x and 2x density, exercise a phone-initialized canvas, small Slice reference, expanded Cubes stage and larger-than-cap desktop. Assert actual WebGL drawing-buffer dimensions match proportional 2048-edge/2x bounds, with one context, no context-loss events, no geometry allocations/uploads and unchanged pose/source/selection. Existing pixel/projection/nearest-picking checks continue on both engines. 2026-10-10: the post-resize full UI suite passed 230 tests; the final viewer suite including display-density listeners passed 130 tests; the final media-query/window-resize regressions passed 4 tests. No skips or retries. Actual browser bitmap/display measurements, screenshots, logs and implementation digests are in `docs/evidence/viewer-resolution/`; repository Trust and lifecycle verification remain separate. Native source is unchanged. + +Pinned Trust passed at implementation `95c1213` with Augur review risk 36 and configured soft provenance degradation. Strict root specs passed at 55/55 files and Hi at 87 criteria. Actual unsigned Codex provenance was recorded after the lane passed; unchanged strict signature/reviewer policy rejects it. Evidence is in `docs/evidence/viewer-resolution/`. Later lifecycle metadata does not change the HTML or tests. From 1269bffeb78bbca596decc28757938543df1a88f Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:45:42 -0600 Subject: [PATCH 41/43] chore(lifecycle): materialize repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera --- .../state.json | 5 ++-- .../verification-attempts.json | 23 +++++++++++++++++++ .../verification.json | 18 +++++++++++++++ specs/ThreeMDViewer/ThreeMDViewer.spec.md | 3 ++- specs/ThreeMDViewer/requirements.md | 1 + 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json create mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json index 453349d..16dd8c3 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json @@ -7,10 +7,11 @@ "title": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", "description": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", "kind": "bug_fix", - "state": "implementing", + "state": "verifying", + "canonical_applied": true, "base_commit": "dab4258541208f8bf6bb5a38f6200a5b348a858e", "created_at": 1791656681, - "updated_at": 1791656808, + "updated_at": 1791657942, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json new file mode 100644 index 0000000..e4d3f51 --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json @@ -0,0 +1,23 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1791657937, + "commit": "cc71e781a3226550611ea09d8637cbaf2e67a1c8", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] + } + ] +} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json new file mode 100644 index 0000000..42dd909 --- /dev/null +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json @@ -0,0 +1,18 @@ +{ + "timestamp": 1791657937, + "commit": "cc71e781a3226550611ea09d8637cbaf2e67a1c8", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] +} diff --git a/specs/ThreeMDViewer/ThreeMDViewer.spec.md b/specs/ThreeMDViewer/ThreeMDViewer.spec.md index 7c1e114..483d7d5 100644 --- a/specs/ThreeMDViewer/ThreeMDViewer.spec.md +++ b/specs/ThreeMDViewer/ThreeMDViewer.spec.md @@ -1,6 +1,6 @@ --- module: ThreeMDViewer -version: 17 +version: 18 status: active files: - web/viewer.html @@ -163,6 +163,7 @@ Acceptance Criteria: | 2026-10-10 | SpecSync | bring-sculpt-slice-editing-to-the-browser-with-a-visual-grid-drawing-tools-undo-and-live-3d-reference: Bring Sculpt slice editing to the browser with a visual grid, drawing tools, undo and live 3D reference | | 2026-10-10 | SpecSync | add-matching-x-y-z-axis-rotation-gizmos-and-precise-camera-steps-to-sculpt-and-the-viewer: Add matching X Y Z axis rotation gizmos and precise camera steps to Sculpt and the viewer | | 2026-10-10 | agent:codex | Repair the frozen small drawable being stretched across Cubes after Slice or phone layout; update only changed bitmap dimensions and retain the context, geometry and camera. | +| 2026-10-10 | SpecSync | repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera: Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity | ## Slice and precise camera parity diff --git a/specs/ThreeMDViewer/requirements.md b/specs/ThreeMDViewer/requirements.md index 647377c..846e491 100644 --- a/specs/ThreeMDViewer/requirements.md +++ b/specs/ThreeMDViewer/requirements.md @@ -65,6 +65,7 @@ Acceptance Criteria: - A fenced grid draws on WebGL2, including about 1400 cubes. A single cell has filled faces from every side. Selection changes edge color while the face interior keeps its glyph color. Camera, zoom, and selection redraw without geometry uploads. Click picking selects the nearest visible cube’s Z slice. - X is the column, Y is the text row with row 0 toward the top, and Z is the plane index. Space, dot, and tab are empty. Keep the 64 by 64 per-plane and 4000-cell caps. - Evidence is VIEWER-6 and the cube tests in `uitests/viewer.spec.mjs`. +- The same 3D context and geometry remain installed when moving between Cubes and the Slice reference or changing display size. The drawable follows the visible pane size and device pixel ratio, bounded to 2x and a proportional 2048-pixel edge cap; unchanged sizes avoid bitmap reallocations. Small-to-large, phone/desktop and Retina transitions remain sharp without changing source, camera, slice or nearest picking. ### REQ-ThreeMDViewer-006 From 57a2db9ac4e98000a36aa9660df39e74aa21e17b Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:45:59 -0600 Subject: [PATCH 42/43] chore(lifecycle): record repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera verification --- .../state.json | 2 +- .../verification-attempts.json | 18 ++++++++++++++++++ .../verification.json | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json index 16dd8c3..1586a5d 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json @@ -11,7 +11,7 @@ "canonical_applied": true, "base_commit": "dab4258541208f8bf6bb5a38f6200a5b348a858e", "created_at": 1791656681, - "updated_at": 1791657942, + "updated_at": 1791657959, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json index e4d3f51..90335fd 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json @@ -18,6 +18,24 @@ "requirement_ids": [ "REQ-ThreeMDViewer-004" ] + }, + { + "timestamp": 1791657954, + "commit": "1269bffeb78bbca596decc28757938543df1a88f", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] } ] } diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json index 42dd909..59c38e4 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json +++ b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json @@ -1,6 +1,6 @@ { - "timestamp": 1791657937, - "commit": "cc71e781a3226550611ea09d8637cbaf2e67a1c8", + "timestamp": 1791657954, + "commit": "1269bffeb78bbca596decc28757938543df1a88f", "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", From 78a94d05da1d21fdbf397cb976546e5d4cc67c2b Mon Sep 17 00:00:00 2001 From: Leif <8268288+0xLeif@users.noreply.github.com> Date: Sat, 10 Oct 2026 12:48:14 -0600 Subject: [PATCH 43/43] Archive verified shared canvas resolution repair --- .../accepted-state.json | 39 +++ .../approvals.json | 7 + .../change.md | 2 +- .../context.md | 0 .../deltas/ThreeMDViewer.md | 0 .../finalization.json | 12 + .../lesson-bundle.md | 52 ++++ .../review-attempts.json | 21 ++ .../review.json | 16 ++ .../state.json | 4 +- .../tasks.md | 0 .../testing.md | 0 .../verification-attempts.json | 255 ++++++++++++++++++ .../verification.json | 214 +++++++++++++++ .../verification-attempts.json | 41 --- .../verification.json | 18 -- 16 files changed, 619 insertions(+), 62 deletions(-) create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/accepted-state.json rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/approvals.json (89%) rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/change.md (97%) rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/context.md (100%) rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/deltas/ThreeMDViewer.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/finalization.json create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/lesson-bundle.md create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review-attempts.json create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review.json rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/state.json (96%) rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/tasks.md (100%) rename .specsync/{changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera => archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera}/testing.md (100%) create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json create mode 100644 .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json delete mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json delete mode 100644 .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/accepted-state.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/accepted-state.json new file mode 100644 index 0000000..82afd6c --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/accepted-state.json @@ -0,0 +1,39 @@ +{ + "schema_version": 1, + "workflow_version": 2, + "workflow_origin_version": 2, + "id": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "slug": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "title": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", + "description": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", + "kind": "bug_fix", + "state": "accepted", + "canonical_applied": true, + "base_commit": "dab4258541208f8bf6bb5a38f6200a5b348a858e", + "created_at": 1791656681, + "updated_at": 1791657999, + "affected_specs": [ + "ThreeMDViewer" + ], + "affected_paths": [ + "web/viewer.html", + "uitests/viewer.spec.mjs", + "specs/ThreeMDViewer", + "docs/evidence/viewer-resolution" + ], + "no_spec_change": false, + "no_spec_change_rationale": null, + "acceptance_criteria": [ + "The shared 3D canvas drawing buffer follows the displayed Cubes or Slice-reference size and device pixel ratio within the existing 2048-edge/2x limits; switching from a small reference or phone viewport to a large stage remains sharp; resizing retains the same WebGL context, geometry and camera/source/selection; Chromium, WebKit and the actual in-app browser verify transitions and picking." + ], + "selected_artifacts": [ + "context", + "testing", + "tasks" + ], + "dependencies": [], + "answers": { + "architecture_risk": "no", + "public_contract": "no" + } +} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json similarity index 89% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json index e6ae11d..e619820 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/approvals.json @@ -36,6 +36,13 @@ "approved_delta_digests": { "ThreeMDViewer": "77b5cd3341a46906bd1c09ba7e2e6c3bff2aa8f9c8e30c453b632c680c52fed9" } + }, + { + "gate": "finalization", + "actor": "specsync:finalization", + "timestamp": 1791657999, + "digest": "35f18f24b91066a63ba3add8c3a8035b64813c30cdce7b5322583a08ad75eb3a", + "note": "Same-PR finalization closing digest" } ], "reopenings": [] diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md similarity index 97% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md index f1590ae..b583897 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/change.md @@ -1,6 +1,6 @@ --- id: repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera -state: implementing +state: archived type: bug_fix base_commit: dab4258541208f8bf6bb5a38f6200a5b348a858e --- diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md similarity index 100% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/context.md diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md similarity index 100% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/deltas/ThreeMDViewer.md diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/finalization.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/finalization.json new file mode 100644 index 0000000..b11b4dd --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/finalization.json @@ -0,0 +1,12 @@ +{ + "schema_version": 2, + "change_id": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "implementation_commit": "57a2db9ac4e98000a36aa9660df39e74aa21e17b", + "implementation_tree": "7f0597b4ae0f13eadb2f00388b1b6c7bb5216796", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "closing_digest": "35f18f24b91066a63ba3add8c3a8035b64813c30cdce7b5322583a08ad75eb3a", + "review_digest": "7ab87f1a1b99acbf5bff08b07a16dc0b0b0f78c182d1b962b8ad72b1e68549bd", + "finalization_digest": "7dce16ee853ce3924ccc051ca1fbc17002d8c7871abb4f89660bd65b83bd4ecf", + "timestamp": 1791657999 +} diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/lesson-bundle.md b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/lesson-bundle.md new file mode 100644 index 0000000..fac5dd1 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/lesson-bundle.md @@ -0,0 +1,52 @@ +# Lesson bundle — repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera + +Material for folding this change's lessons into the affected specs' `context.md`. +Synthesise from what actually happened below; do not restate the change description. + +## What this change was + +- **Title**: Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity +- **Kind**: BugFix +- **Specs**: ThreeMDViewer +- **Paths**: web/viewer.html, uitests/viewer.spec.mjs, specs/ThreeMDViewer, docs/evidence/viewer-resolution +- **Acceptance**: The shared 3D canvas drawing buffer follows the displayed Cubes or Slice-reference size and device pixel ratio within the existing 2048-edge/2x limits; switching from a small reference or phone viewport to a large stage remains sharp; resizing retains the same WebGL context, geometry and camera/source/selection; Chromium, WebKit and the actual in-app browser verify transitions and picking. + +## Evidence + +- Verification commit: `57a2db9ac4e98000a36aa9660df39e74aa21e17b` +- Base commit: `dab4258541208f8bf6bb5a38f6200a5b348a858e` +- Verified by: `specsync check --spec ThreeMDViewer --strict` + +## From the change's context.md + +# Context + +Leif reported the existing browser preview was blurry after the approved Slice/camera work. Actual DOM and screenshot inspection found the shared 3D canvas bitmap at 368x322 while its Cubes display was 1099x911. The bitmap was frozen after initial context creation as a Safari workaround; a phone/reference-sized initialization was later stretched across a desktop stage. + +This repairs the existing approved viewer/Sculpt-quality behavior under Leif's standing request to continue improving the browser and fix the viewer PR. It adds no editing tool, storage behavior, renderer or camera convention. Preserve the single WebGL context, installed mesh, source, selection, pose, 2x density cap and 2048 pixel edge cap. Resize only the drawable when its required dimensions change; validate actual in-app WebKit behavior rather than assuming every resize loses its context. + +## From the change's testing.md + +# Testing + +At device pixel ratios 1 and 2, initialize a phone-sized Cubes stage, switch through Slice's small reference and expand/resize to desktop and larger-than-cap layouts. Check actual drawable width/height against proportional 2048-edge/2x bounds, the same context/program/mesh, zero context-loss events and zero subsequent geometry uploads. Preserve source, selected slice, camera pose and nearest picking. Run existing projection, pixel, Slice and navigation regressions on Chromium and WebKit and inspect the actual in-app WebKit output. Root strict specs and pinned Trust must pass; actual unsigned agent:codex provenance remains separate from a permitted signature or human diff review. + +## Requirement evidence + +| ID | Canonical | Evidence | +| --- | --- | --- | +| REQ-ThreeMDViewer-004 | REQ-ThreeMDViewer-004 | New actual drawable-density and context-retention regression, existing GPU pixel/projection/picking tests, in-app browser before/after measurements and screenshot. | + +## Current results + +The complete post-resize UI suite passed 230 tests. After final display-density listeners, the viewer suite passed 130 tests. The final media-query/window-resize density regressions passed 4 tests. All ran on Chromium and WebKit without skips or retries. Actual in-app bitmap/display measurements and screenshots, test logs and implementation digests are in `docs/evidence/viewer-resolution/`. Pinned Trust, actual provenance and finalization remain separately evidenced. + +## Repository verification and provenance + +Pinned Trust 1.2.2 with Fledge 1.7.2 passed on implementation commit `95c1213886b853a7b945fd833a5af02fa0f8128d`; Augur returned review at risk 36, with configured soft provenance degradation. The full configured verification lane passed. Strict root specs passed at 55/55 files and Hi passed 87 criteria. Source digests above bind the browser results to this implementation; later lifecycle/materialization records do not change the HTML or tests. + +Actual unsigned agent:codex attestation was recorded after the lane passed. The unchanged strict Attest policy rejects the unavailable permitted signature and reviewer allow-list, as shown in `attest-policy.json`. This is not a human review or signed provenance claim, and no policy was changed. Lifecycle closure is recorded separately in its supported receipt. + +## Where these lessons go + +- `specs/ThreeMDViewer/context.md` diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review-attempts.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review-attempts.json new file mode 100644 index 0000000..3b71f2a --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review-attempts.json @@ -0,0 +1,21 @@ +{ + "schema_version": 1, + "reviews": [ + { + "schema_version": 2, + "change_id": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "reviewer": "agent:codex", + "provenance": { + "schema_version": 1, + "provider": "github_actions_check", + "required_check": "SpecSync scoped review" + }, + "verdict": "pass", + "implementation_commit": "57a2db9ac4e98000a36aa9660df39e74aa21e17b", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "timestamp": 1791657975 + } + ] +} diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review.json new file mode 100644 index 0000000..86102b6 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/review.json @@ -0,0 +1,16 @@ +{ + "schema_version": 2, + "change_id": "repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera", + "reviewer": "agent:codex", + "provenance": { + "schema_version": 1, + "provider": "github_actions_check", + "required_check": "SpecSync scoped review" + }, + "verdict": "pass", + "implementation_commit": "57a2db9ac4e98000a36aa9660df39e74aa21e17b", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "timestamp": 1791657975 +} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json similarity index 96% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json index 1586a5d..59e698c 100644 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/state.json @@ -7,11 +7,11 @@ "title": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", "description": "Repair blurry Cubes and Slice canvases after view and display-size changes while retaining the WebGL context and camera parity", "kind": "bug_fix", - "state": "verifying", + "state": "archived", "canonical_applied": true, "base_commit": "dab4258541208f8bf6bb5a38f6200a5b348a858e", "created_at": 1791656681, - "updated_at": 1791657959, + "updated_at": 1791658049, "affected_specs": [ "ThreeMDViewer" ], diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md similarity index 100% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/tasks.md diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md similarity index 100% rename from .specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md rename to .specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/testing.md diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json new file mode 100644 index 0000000..7424baa --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json @@ -0,0 +1,255 @@ +{ + "schema_version": 1, + "attempts": [ + { + "timestamp": 1791657937, + "commit": "cc71e781a3226550611ea09d8637cbaf2e67a1c8", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] + }, + { + "timestamp": 1791657954, + "commit": "1269bffeb78bbca596decc28757938543df1a88f", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] + }, + { + "timestamp": 1791657954, + "commit": "57a2db9ac4e98000a36aa9660df39e74aa21e17b", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "acceptance_input_digest": "474024b8d244e1b0e66609fa2555e10bb14829248a2539c9606188898d4020ea", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": "docs/evidence/viewer-resolution", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "1181f446a18468191a072ade800c6ab693b2ed1dadc57d03da27b41b9fc3a3ff", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "7559047d56b41d7b92476e8880be512074186c309ded7d33de63bb8479220e1d", + "entry_digest": "df4cbb2e9c537933efbe70a8083143254b2df01cbb9c33eb3ce51b53282c4d51", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/attest-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "ebf8266fd7a37f7000ffb0ac1dda354903618d47f204d8c0d6e023b3f03945ea", + "entry_digest": "1345beebaa173db2e613589ce7040659a6b66a837c96dfa59562a4b29e2c53f4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/attest-policy.json", + "kind": "file", + "mode": 33188, + "payload_digest": "75e89fd087362ae70a2e1edc8d998953de6655773018babea94783230a137bdf", + "entry_digest": "9e07cd2c092474a9ba50c4f93520a98993c819ecfc09c71fee13e7da5876741f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/browser-after.png", + "kind": "file", + "mode": 33188, + "payload_digest": "32ab5ee993c52f5c17b5744bdd10326d47f132567d868042d63bdee4cfbfccf9", + "entry_digest": "0144a6e8335bb916f98f9f5d82e0cb5f1892f9daa70cf0ae9677c1787e051cd0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/browser-before.png", + "kind": "file", + "mode": 33188, + "payload_digest": "b72015dc9ed9c634e022dda0f4c7021d56edd4af1e23f786180bf5df5c826eac", + "entry_digest": "586995ccca4e70d99751ad9ff94aeef7cd26b785c066ef25e0a47a2c132659ec", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/browser-full.log", + "kind": "file", + "mode": 33188, + "payload_digest": "d7a1034a41ea1aa87f04c8f0699af8aa692b6d33ffe7d7f990931797d5a28d51", + "entry_digest": "ea458237acf04e3fab7bf3b5b321b5a9a837bddb0ee080e3154dfb7ed23b7a9a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/density-final.log", + "kind": "file", + "mode": 33188, + "payload_digest": "4ea0c6f45736a3d53a0678057abfb45a33c26afb515501e668fff7b2a7aaffa9", + "entry_digest": "d8cdc825d3cb0efd3d9baf285e5c59b5580a0f7ef75940f00e2d6cbe803aaf24", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/strict-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "e65b3be05140229cc195848694ecf5457afad42551f7d52769e00babee0b6f4f", + "entry_digest": "cdbe0c731a4a6ad2aef535556b8be975bf6059179a2ef3aca6e2f8516ad73784", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/trust-implementation.log", + "kind": "file", + "mode": 33188, + "payload_digest": "f6b524e5e16be131f202250e7ad006b61ffbce3c3bdf6ed0877aac0e80068227", + "entry_digest": "fa15062abb14bd0af5575017896f5f36cf81141dcbf55b918fc45f2d317b1117", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/viewer-final.log", + "kind": "file", + "mode": 33188, + "payload_digest": "9f08854409164c2d0046121631cb23ba537a0a1ff3b1f5504a402da9992d3f31", + "entry_digest": "45b6f6e6dfb9193e42dee450258ac77bb2f259a058453275c4617d75397d2bf5", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/ThreeMDViewer", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "b53a01354acef7fb830687d9789c70f85c60f43e94da4a2dd0816c771a3bf773", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/ThreeMDViewer.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "bac308a20661b3e1b61a6851c67de191c89d5a7246ba84dfcee459e1fb3f06da", + "entry_digest": "a60eb3fe5bb7d6dc19fc57f9787fe7757fc9e472697f56c68e6c9dc024e5a190", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "f09326e825a394cb101529b853966c6b5322a2fc3badf79fb1fd2f9d320ef047", + "entry_digest": "336da9d0cb28b6c6ddfc58263c1a3b07f2a4c39c63d37a989b40844d5d90c17d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3dac32212b6c3e224405474d1d7691a739cc502cce4b0bfd3159b5a44dbb46d0", + "entry_digest": "b58e0f42ebd2f6b8eaa9cdc1bd7970d34031262b334b43bf9de66a56dcedf382", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1067ddf384b6f388c737b630526ea78a96b74af4a4592c3f9b53ec6ee4098eae", + "entry_digest": "59ae09c0a423c2b88af674e7bc7ed35b795891289ea775b3708575e05dc8225d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6165442a33a7522678bc97daf88f790ac7dbe7235126760dc766909a5d7bb814", + "entry_digest": "04aa5d18efa83971c44d2f4412ff5a176ce1666ff86be9206c0262ed6d064c3d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "uitests/viewer.spec.mjs", + "kind": "file", + "mode": 33188, + "payload_digest": "59894ffd439caff704f34d3fba39425e991f854fcfe83a73aca673b0883c1c97", + "entry_digest": "1af3072d0be2fb62f3b2f714b5cba967db575341c2b52d922246a262dc36302c", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "web/viewer.html", + "kind": "file", + "mode": 33188, + "payload_digest": "d5c226e7ccb6b46c7e462c6d72a89772138080dce9269f0813cd0979d10116b8", + "entry_digest": "99be08aa8855f3adc79655fc5802caee2260cc034f786496de965bf99a78cd3c", + "owners": [ + "ThreeMDViewer" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] + } + ] +} diff --git a/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json new file mode 100644 index 0000000..5fcc8f7 --- /dev/null +++ b/.specsync/archive/changes/2026-10-10-repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json @@ -0,0 +1,214 @@ +{ + "timestamp": 1791657954, + "commit": "57a2db9ac4e98000a36aa9660df39e74aa21e17b", + "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", + "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", + "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", + "acceptance_input_digest": "474024b8d244e1b0e66609fa2555e10bb14829248a2539c9606188898d4020ea", + "acceptance_manifest": { + "schema_version": 1, + "entries": [ + { + "path": "docs/evidence/viewer-resolution", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "1181f446a18468191a072ade800c6ab693b2ed1dadc57d03da27b41b9fc3a3ff", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/README.md", + "kind": "file", + "mode": 33188, + "payload_digest": "7559047d56b41d7b92476e8880be512074186c309ded7d33de63bb8479220e1d", + "entry_digest": "df4cbb2e9c537933efbe70a8083143254b2df01cbb9c33eb3ce51b53282c4d51", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/attest-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "ebf8266fd7a37f7000ffb0ac1dda354903618d47f204d8c0d6e023b3f03945ea", + "entry_digest": "1345beebaa173db2e613589ce7040659a6b66a837c96dfa59562a4b29e2c53f4", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/attest-policy.json", + "kind": "file", + "mode": 33188, + "payload_digest": "75e89fd087362ae70a2e1edc8d998953de6655773018babea94783230a137bdf", + "entry_digest": "9e07cd2c092474a9ba50c4f93520a98993c819ecfc09c71fee13e7da5876741f", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/browser-after.png", + "kind": "file", + "mode": 33188, + "payload_digest": "32ab5ee993c52f5c17b5744bdd10326d47f132567d868042d63bdee4cfbfccf9", + "entry_digest": "0144a6e8335bb916f98f9f5d82e0cb5f1892f9daa70cf0ae9677c1787e051cd0", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/browser-before.png", + "kind": "file", + "mode": 33188, + "payload_digest": "b72015dc9ed9c634e022dda0f4c7021d56edd4af1e23f786180bf5df5c826eac", + "entry_digest": "586995ccca4e70d99751ad9ff94aeef7cd26b785c066ef25e0a47a2c132659ec", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/browser-full.log", + "kind": "file", + "mode": 33188, + "payload_digest": "d7a1034a41ea1aa87f04c8f0699af8aa692b6d33ffe7d7f990931797d5a28d51", + "entry_digest": "ea458237acf04e3fab7bf3b5b321b5a9a837bddb0ee080e3154dfb7ed23b7a9a", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/density-final.log", + "kind": "file", + "mode": 33188, + "payload_digest": "4ea0c6f45736a3d53a0678057abfb45a33c26afb515501e668fff7b2a7aaffa9", + "entry_digest": "d8cdc825d3cb0efd3d9baf285e5c59b5580a0f7ef75940f00e2d6cbe803aaf24", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/strict-implementation.json", + "kind": "file", + "mode": 33188, + "payload_digest": "e65b3be05140229cc195848694ecf5457afad42551f7d52769e00babee0b6f4f", + "entry_digest": "cdbe0c731a4a6ad2aef535556b8be975bf6059179a2ef3aca6e2f8516ad73784", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/trust-implementation.log", + "kind": "file", + "mode": 33188, + "payload_digest": "f6b524e5e16be131f202250e7ad006b61ffbce3c3bdf6ed0877aac0e80068227", + "entry_digest": "fa15062abb14bd0af5575017896f5f36cf81141dcbf55b918fc45f2d317b1117", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "docs/evidence/viewer-resolution/viewer-final.log", + "kind": "file", + "mode": 33188, + "payload_digest": "9f08854409164c2d0046121631cb23ba537a0a1ff3b1f5504a402da9992d3f31", + "entry_digest": "45b6f6e6dfb9193e42dee450258ac77bb2f259a058453275c4617d75397d2bf5", + "owners": [ + "@exact:delivery" + ] + }, + { + "path": "specs/ThreeMDViewer", + "kind": "non_file", + "mode": 0, + "payload_digest": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "entry_digest": "b53a01354acef7fb830687d9789c70f85c60f43e94da4a2dd0816c771a3bf773", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/ThreeMDViewer.spec.md", + "kind": "file", + "mode": 33188, + "payload_digest": "bac308a20661b3e1b61a6851c67de191c89d5a7246ba84dfcee459e1fb3f06da", + "entry_digest": "a60eb3fe5bb7d6dc19fc57f9787fe7757fc9e472697f56c68e6c9dc024e5a190", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/context.md", + "kind": "file", + "mode": 33188, + "payload_digest": "f09326e825a394cb101529b853966c6b5322a2fc3badf79fb1fd2f9d320ef047", + "entry_digest": "336da9d0cb28b6c6ddfc58263c1a3b07f2a4c39c63d37a989b40844d5d90c17d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/requirements.md", + "kind": "file", + "mode": 33188, + "payload_digest": "3dac32212b6c3e224405474d1d7691a739cc502cce4b0bfd3159b5a44dbb46d0", + "entry_digest": "b58e0f42ebd2f6b8eaa9cdc1bd7970d34031262b334b43bf9de66a56dcedf382", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/tasks.md", + "kind": "file", + "mode": 33188, + "payload_digest": "1067ddf384b6f388c737b630526ea78a96b74af4a4592c3f9b53ec6ee4098eae", + "entry_digest": "59ae09c0a423c2b88af674e7bc7ed35b795891289ea775b3708575e05dc8225d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "specs/ThreeMDViewer/testing.md", + "kind": "file", + "mode": 33188, + "payload_digest": "6165442a33a7522678bc97daf88f790ac7dbe7235126760dc766909a5d7bb814", + "entry_digest": "04aa5d18efa83971c44d2f4412ff5a176ce1666ff86be9206c0262ed6d064c3d", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "uitests/viewer.spec.mjs", + "kind": "file", + "mode": 33188, + "payload_digest": "59894ffd439caff704f34d3fba39425e991f854fcfe83a73aca673b0883c1c97", + "entry_digest": "1af3072d0be2fb62f3b2f714b5cba967db575341c2b52d922246a262dc36302c", + "owners": [ + "ThreeMDViewer" + ] + }, + { + "path": "web/viewer.html", + "kind": "file", + "mode": 33188, + "payload_digest": "d5c226e7ccb6b46c7e462c6d72a89772138080dce9269f0813cd0979d10116b8", + "entry_digest": "99be08aa8855f3adc79655fc5802caee2260cc034f786496de965bf99a78cd3c", + "owners": [ + "ThreeMDViewer" + ] + } + ] + }, + "passed": true, + "commands": [ + { + "command": "specsync check --spec ThreeMDViewer --strict", + "success": true, + "exit_code": 0 + } + ], + "requirement_ids": [ + "REQ-ThreeMDViewer-004" + ] +} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json deleted file mode 100644 index 90335fd..0000000 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification-attempts.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "schema_version": 1, - "attempts": [ - { - "timestamp": 1791657937, - "commit": "cc71e781a3226550611ea09d8637cbaf2e67a1c8", - "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", - "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", - "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-004" - ] - }, - { - "timestamp": 1791657954, - "commit": "1269bffeb78bbca596decc28757938543df1a88f", - "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", - "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", - "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-004" - ] - } - ] -} diff --git a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json b/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json deleted file mode 100644 index 59c38e4..0000000 --- a/.specsync/changes/repair-blurry-cubes-and-slice-canvases-after-view-and-display-size-changes-while-retaining-the-webgl-context-and-camera/verification.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "timestamp": 1791657954, - "commit": "1269bffeb78bbca596decc28757938543df1a88f", - "contract_digest": "2434816b883b109a6be3b8d0f9f72837258bc21346df7a0d4357d9df27fe8dd0", - "execution_digest": "a67030d2d4fae6350ec00846e2a062e089570c761064ec0b92e2f51bc1fb7ceb", - "workspace_digest": "8d823c7fee2b7188d8da38049f5c4691eed8c49ad8f71a6b4210edcb9d2492b3", - "passed": true, - "commands": [ - { - "command": "specsync check --spec ThreeMDViewer --strict", - "success": true, - "exit_code": 0 - } - ], - "requirement_ids": [ - "REQ-ThreeMDViewer-004" - ] -}