From ee244d8caccacbc6e4dc120b205395a9d32222dd Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:34:51 -0700 Subject: [PATCH 01/24] fix(render-core): clear typecheck errors in link-object and wholeobject tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ViewerRoute is a discriminated union — accessing objectId/noteId requires narrowing on view === "exhibit" first. The W3CAnnotation → Record cast needs an unknown intermediate since the extension key isn't part of the nominal type. --- packages/render-core/src/link/link-object.test.ts | 6 ++++-- packages/render-core/src/spine/wholeobject.test.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/render-core/src/link/link-object.test.ts b/packages/render-core/src/link/link-object.test.ts index c90b5255..365860b9 100644 --- a/packages/render-core/src/link/link-object.test.ts +++ b/packages/render-core/src/link/link-object.test.ts @@ -27,8 +27,10 @@ describe("Object cite route grammar (route.ts)", () => { expect(parseRoute(routeToHash(r))).toEqual(r); }); it("does not confuse `/o/` with the `/a/` note tail", () => { - expect(parseRoute("#/voynich/a/n1").objectId).toBeUndefined(); - expect(parseRoute("#/voynich/o/f1r").noteId).toBeUndefined(); + const noteRoute = parseRoute("#/voynich/a/n1"); + expect(noteRoute.view === "exhibit" ? noteRoute.objectId : undefined).toBeUndefined(); + const objectRoute = parseRoute("#/voynich/o/f1r"); + expect(objectRoute.view === "exhibit" ? objectRoute.noteId : undefined).toBeUndefined(); }); }); diff --git a/packages/render-core/src/spine/wholeobject.test.ts b/packages/render-core/src/spine/wholeobject.test.ts index 5933353f..01969f49 100644 --- a/packages/render-core/src/spine/wholeobject.test.ts +++ b/packages/render-core/src/spine/wholeobject.test.ts @@ -45,7 +45,7 @@ describe("archie:wholeObject = region-override (the closed seam)", () => { const { log } = appendNew([], { target: region("xywh=pixel:0,0,10,10"), wholeObject: true, lastEditor: editor }); const head = toHeadsPage(log, "p").items[0]!; - expect((head as Record)["archie:wholeObject"]).toBe(true); + expect((head as unknown as Record)["archie:wholeObject"]).toBe(true); expect(wholeObjectFlagOf(head)).toBe(true); // the reader the viewer already calls now sees a real value const back = fromHistory(Object.values(toHistory(log).pages)); From 7415fe253ff24ca3bfbc38e81554ed7f5a38c4d7 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:37:21 -0700 Subject: [PATCH 02/24] fix(render-mount): resolve addOverlay type mismatch between FrameViewerLike and OSD Viewer @types/openseadragon declares OverlayOptions.element as HTMLElement-only and location as Point|Rect, but frame-overlay.ts deliberately keeps FrameViewerLike duck-typed and decoupled from OSD's concrete types (so it stays test-mockable without importing OSD). Narrow the element type to match OSD's real contract, cast the SVG element at its one call site (SVG works fine at runtime, OSD's types just don't say so), and assert Viewer satisfies FrameViewerLike once at the mount.ts wiring boundary instead of coupling the interface back to OSD. --- packages/render-mount/src/frame-overlay.ts | 6 ++++-- packages/render-mount/src/mount.ts | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/render-mount/src/frame-overlay.ts b/packages/render-mount/src/frame-overlay.ts index cd9cf05d..956e9abf 100644 --- a/packages/render-mount/src/frame-overlay.ts +++ b/packages/render-mount/src/frame-overlay.ts @@ -11,7 +11,9 @@ import type { FrameOverlay } from "./surface.js"; /** The minimal OSD viewer surface this overlay needs — keeps the module decoupled from the full OSD type. */ export interface FrameViewerLike { - addOverlay(options: { element: HTMLElement | SVGElement; location: unknown }): void; + // OSD's own OverlayOptions.element type is HTMLElement-only (@types/openseadragon), even though + // an SVGElement works fine at runtime — the SVG frame below is cast at its one call site. + addOverlay(options: { element: HTMLElement; location: unknown }): void; removeOverlay(element: HTMLElement | SVGElement): void; world: { getItemAt(i: number): { getBounds(immediately?: boolean): unknown } | undefined }; addOnceHandler?(name: string, handler: () => void): void; @@ -86,7 +88,7 @@ export function createFrameOverlay(viewer: FrameViewerLike): FrameOverlayControl svg.append(rect(frame.colour, "1.5", true)); // the quiet colour border — the click target // Anchor to the OBJECT: OSD positions + sizes the SVG to the image's viewport Rect every render frame, // so the border tracks the object through pan/zoom instead of sticking to the viewport edges. - viewer.addOverlay({ element: svg, location: item.getBounds() }); + viewer.addOverlay({ element: svg as unknown as HTMLElement, location: item.getBounds() }); frameEl = svg; }; diff --git a/packages/render-mount/src/mount.ts b/packages/render-mount/src/mount.ts index 6d4cf66f..875819dd 100644 --- a/packages/render-mount/src/mount.ts +++ b/packages/render-mount/src/mount.ts @@ -16,7 +16,7 @@ import type { ImageAnnotation, W3CImageAnnotation, DrawingStyle, DrawingStyleExp import { mountPlugin } from "@annotorious/plugin-tools"; import { resolveTileSource, isDegenerateSelectorValue, selectorOf, selectorBBox, regionPixelRect } from "@render/core"; import { dispatchFitBounds, applyFitBounds, clampedFitRect, type FitOptions, type ViewportLike } from "./fitbounds.js"; -import { createFrameOverlay } from "./frame-overlay.js"; +import { createFrameOverlay, type FrameViewerLike } from "./frame-overlay.js"; import { GestureGuard } from "./gesture-guard.js"; import { zoomBand } from "./zoom-band.js"; import { xyzTileSource } from "./xyz.js"; @@ -248,7 +248,11 @@ export async function createMount(container: HTMLElement, opts: MountOptions): P // Coverage-border overlay (7e1f) — a standalone rendering concern (createFrameOverlay). It frames the // WHOLE OBJECT: the SVG is added as an OSD overlay at the image's bounds, so it tracks the object through // pan/zoom (not a fixed viewport border). setFrame re-draws (replacing any current frame); null clears it. - const frameOverlay = createFrameOverlay(viewer); + // FrameViewerLike is deliberately a minimal duck-typed capability (frame-overlay.ts stays + // decoupled from OSD's concrete Point/Rect/OverlayOptions types); OSD's real Viewer satisfies it + // at runtime (addOverlay takes {element, location}) but its own types are narrower/wider than + // the duck type in ways TS can't verify structurally — asserted once here, at the wiring point. + const frameOverlay = createFrameOverlay(viewer as unknown as FrameViewerLike); // Shared rect math for markerScreenRect(s): selector bbox in image px → viewer-element coords + // the container's page offset, so a position:fixed anchor works regardless of layout (ADR-0006). From 8693795bd993667de037bc72bbe1582b8d0fa391 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:39:27 -0700 Subject: [PATCH 03/24] fix(render-mount): clear noUncheckedIndexedAccess/exactOptionalPropertyTypes test errors Array/NodeList indexing and open-handler lookups return T|undefined under noUncheckedIndexedAccess; assert non-null with ! at the known-populated indices (same idiom as existing render-core tests). The innerHTML spy's PropertyDescriptor.get needs a conditional spread instead of `get: desc?.get` since exactOptionalPropertyTypes rejects an explicit undefined on an optional property. render-mount typecheck (`pnpm --filter @render/mount exec tsc --noEmit`) is now fully green; all 116 tests still pass. --- .../render-mount/src/frame-overlay.test.ts | 10 +++---- .../src/read-overlay-security.test.ts | 8 ++--- .../render-mount/src/read-overlay.test.ts | 30 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/render-mount/src/frame-overlay.test.ts b/packages/render-mount/src/frame-overlay.test.ts index 24b82e65..11b7a8a4 100644 --- a/packages/render-mount/src/frame-overlay.test.ts +++ b/packages/render-mount/src/frame-overlay.test.ts @@ -34,7 +34,7 @@ describe("createFrameOverlay.draw", () => { const v = fakeViewer(); createFrameOverlay(v).draw(frame()); expect(v.overlays).toHaveLength(1); - const svg = v.overlays[0].element as SVGSVGElement; + const svg = v.overlays[0]!.element as SVGSVGElement; expect(svg.tagName.toLowerCase()).toBe("svg"); expect(svg.getAttribute("viewBox")).toBe("0 0 100 100"); expect(svg.style.pointerEvents).toBe("none"); // centre stays pan/zoom-free @@ -43,9 +43,9 @@ describe("createFrameOverlay.draw", () => { it("draws a halo rect + a clickable colour rect carrying the frame colour", () => { const v = fakeViewer(); createFrameOverlay(v).draw(frame()); - const rects = (v.overlays[0].element as SVGSVGElement).querySelectorAll("rect"); + const rects = (v.overlays[0]!.element as SVGSVGElement).querySelectorAll("rect"); expect(rects).toHaveLength(2); - const colour = rects[1]; + const colour = rects[1]!; expect(colour.getAttribute("stroke")).toBe("#c83"); expect((colour as SVGElement).style.pointerEvents).toBe("stroke"); // only the line is the hit target expect(colour.getAttribute("vector-effect")).toBe("non-scaling-stroke"); @@ -55,7 +55,7 @@ describe("createFrameOverlay.draw", () => { const v = fakeViewer(); const onActivate = vi.fn(); createFrameOverlay(v).draw(frame(onActivate)); - const colour = (v.overlays[0].element as SVGSVGElement).querySelectorAll("rect")[1]; + const colour = (v.overlays[0]!.element as SVGSVGElement).querySelectorAll("rect")[1]!; colour.dispatchEvent(new Event("click")); expect(onActivate).toHaveBeenCalledTimes(1); }); @@ -68,7 +68,7 @@ describe("createFrameOverlay.draw", () => { // simulate the image opening — but it still has no item in this fake, so re-queues; flip to ready: const ready = fakeViewer(); Object.assign(v.world, ready.world); - v.openHandlers[0](); + v.openHandlers[0]!(); expect(v.overlays).toHaveLength(1); }); diff --git a/packages/render-mount/src/read-overlay-security.test.ts b/packages/render-mount/src/read-overlay-security.test.ts index 99e142ff..0c70ec91 100644 --- a/packages/render-mount/src/read-overlay-security.test.ts +++ b/packages/render-mount/src/read-overlay-security.test.ts @@ -37,7 +37,7 @@ describe("STANDING: hostile SvgSelector renders as geometry only — never inner it("(b) the drawn points attribute = ONLY the parsed numeric coords", () => { const v = fakeViewer(); createReadOnlyOverlay(v).setAnnotations([hostileAnn]); - const svg = v.overlays[0].element as SVGSVGElement; + const svg = v.overlays[0]!.element as SVGSVGElement; const poly = svg.querySelector("polygon")!; expect(poly.getAttribute("points")).toBe("0,0 100,0 50,80"); // bbox-local of the 3 valid points }); @@ -45,7 +45,7 @@ describe("STANDING: hostile SvgSelector renders as geometry only — never inner it("(a) no overlay node's innerHTML contains ")]); - const label = (v.overlays[0].element as SVGSVGElement).getAttribute("aria-label")!; + const label = (v.overlays[0]!.element as SVGSVGElement).getAttribute("aria-label")!; expect(label).toBe("annotation p"); expect(label).not.toContain("<"); }); From 8de4a8f73fbe43ab3416077c95b0f3550016b469 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:41:50 -0700 Subject: [PATCH 04/24] fix(studio): delete dead duplicate ObjectMeta/ExhibitMeta/LibraryMeta interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit store.ts already re-exported these as type aliases of @render/core's WorkingObjectMeta/WorkingExhibitMeta/WorkingLibraryMeta (the Q-3 archie-persistence migration), but the old local interface declarations were never deleted — same field lists, same shapes, just stale. TS reported them as conflicting exported declarations, and their remaining RightsFields/MediaType/Section/Reading references as unresolvable (those imports were dropped when the migration landed). Re-import the Working* types under local aliases so both the file's own usages and the re-export contract for external importers (library-meta.svelte.ts, library-meta-reducers.ts, publish-flows.svelte.ts, LibraryHome.svelte) keep working. --- apps/studio/src/store.ts | 62 ++++++---------------------------------- 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/apps/studio/src/store.ts b/apps/studio/src/store.ts index f70a18fc..c67fb363 100644 --- a/apps/studio/src/store.ts +++ b/apps/studio/src/store.ts @@ -7,17 +7,18 @@ // {PROJECT}/annotations/ — the "sample" exhibit's annotations (LEGACY path, // kept so pre-multi-exhibit work isn't orphaned) // {PROJECT}/exhibits/{slug}/annotations/ — every OTHER exhibit's annotations -import { FsaFilesystem, type FsDirectory, type WorkingLibraryMeta, type LayoutType } from "@render/core"; - // The persisted working-store SHAPES live in core now (Q-3 archie-persistence: the Viewer's live // source reads the same format via loadWorkingLibrary). Re-exported under their original Studio // names so import sites stay stable; this module remains the WRITER of the layout. -export type { - WorkingObjectProvenance as ObjectProvenance, - WorkingObjectMeta as ObjectMeta, - WorkingExhibitMeta as ExhibitMeta, - WorkingLibraryMeta as LibraryMeta, +import { + FsaFilesystem, + type FsDirectory, + type WorkingObjectProvenance as ObjectProvenance, + type WorkingObjectMeta as ObjectMeta, + type WorkingExhibitMeta as ExhibitMeta, + type WorkingLibraryMeta as LibraryMeta, } from "@render/core"; +export type { ObjectProvenance, ObjectMeta, ExhibitMeta, LibraryMeta }; const PROJECT = "archie-demo-project"; const SAMPLE_SLUG = "sample"; @@ -45,53 +46,6 @@ export async function openExhibitAnnotationsDir(slug: string): Promise1 object → grid, else single). Kept OPTIONAL for back-compat read-tolerance — - * legacy stored data is harmless and IGNORED; the Studio NEVER writes this field anymore. `LayoutType` - * imported from render-core so this stays the single source of truth (no duplicated string union). */ - layout?: LayoutType; - /** RESERVED (§43 reading-MODE axis) — v1.1 pacing variant (slideshow/scrollytelling). Unused in v1. */ - mode?: string; - objects: ObjectMeta[]; - /** Ordered narrative sections (the authored spine; IIIF Ranges at publish). Present for narrative exhibits. */ - sections?: Section[]; - /** The exhibit's curated Readings (interpretive passes; ADR-0007). A note references one by id (`record.reading`). */ - readings?: Reading[]; - /** Bundled defaults only: bump when the seeded notes change so the reconcile reseeds (P0 fixture iteration). */ - seedVersion?: number; -} -/** The authored library structure persisted at `{PROJECT}/library.json`. Carries the library-level - * identity (`title`/`summary`) + `RightsFields` (collection credit/license). `title`/`summary` were - * previously hardcoded in buildFullLibrary; now authorable so the Library has a home (rights grill Q6). */ -export interface LibraryMeta extends RightsFields { - title?: string; - summary?: string; - exhibits: ExhibitMeta[]; -} - /** Read the authored library structure. Null if OPFS unsupported or nothing authored yet. */ export async function loadLibraryMeta(): Promise { const project = await openProjectDir(); From 9a1aa3382a624146087f0d656d04ba07907dcd7c Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:45:50 -0700 Subject: [PATCH 05/24] fix(studio,viewer): type the Map/geo path as XyzTileSource, not the full union MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit geoBasemap, AddMapModal's tileSource, and addMapObject's parameter were all annotated TileSourceDescriptor (the XyzTileSource | DziTileSource union) even though a Map is always the xyz variant — the annotation widened the literal and erased that. geo-notes.ts's geoLabelOf/geoForTarget then failed calling core's pixelToLngLat/lngLatToPixel, which need Extentish (tileSize+maxZoom, meaningless for a DZI pyramid). Narrow all four to XyzTileSource: fixes the typecheck errors and, as a side effect, makes it a type error to ever feed a DZI descriptor into the geo/Web-Mercator math, which was always nonsensical. --- apps/studio/src/AddMapModal.svelte | 6 +++--- apps/studio/src/geo-notes.ts | 9 +++++---- apps/studio/src/ingest-flows.ts | 4 ++-- apps/viewer/fixtures/geo.ts | 4 ++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/apps/studio/src/AddMapModal.svelte b/apps/studio/src/AddMapModal.svelte index 381bc65d..67736585 100644 --- a/apps/studio/src/AddMapModal.svelte +++ b/apps/studio/src/AddMapModal.svelte @@ -3,10 +3,10 @@ // permit static-site embedding, attribution baked in → resolves D6), set the bounded extent on a // pan/zoom world locator (drag the box / drag handles to clamp · drag the map to pan · wheel/± to zoom), // name it; emits a tileSource descriptor + label. Bounds fields + presets remain for precision. - import { lngLatToPixel, pixelToLngLat, type TileSourceDescriptor } from "@render/core"; + import { lngLatToPixel, pixelToLngLat, type XyzTileSource } from "@render/core"; let { onadd, onclose }: { - onadd: (m: { label: string; tileSource: TileSourceDescriptor }) => void; + onadd: (m: { label: string; tileSource: XyzTileSource }) => void; onclose: () => void; } = $props(); @@ -130,7 +130,7 @@ function submit() { if (!valid) return; const base = { kind: "xyz" as const, tileSize: 256, minZoom: 0, maxZoom, bounds: [west, south, east, north] as [number, number, number, number] }; - const tileSource: TileSourceDescriptor = useCustom + const tileSource: XyzTileSource = useCustom ? { ...base, template: customTemplate.trim(), ...(customAttribution.trim() ? { attribution: customAttribution.trim() } : {}) } : { ...base, template: provider.template, attribution: provider.attribution }; onadd({ label: label.trim() || `${provider.name} map`, tileSource }); diff --git a/apps/studio/src/geo-notes.ts b/apps/studio/src/geo-notes.ts index 54efd939..fdce0d87 100644 --- a/apps/studio/src/geo-notes.ts +++ b/apps/studio/src/geo-notes.ts @@ -1,11 +1,12 @@ // Geo-note selector math (the DOMINO cut out of App.svelte): the two pure helpers that turn a note's // pixel selector / stored geo-truth into a lng/lat readout, and a drawn region's WORLD-pixel selector // into its lng/lat anchor. Both took the reactive `currentTileSource` via closure in App.svelte; here -// they take the `TileSourceDescriptor` explicitly, so they are pure and unit-testable. The underlying +// they take the map's `XyzTileSource` explicitly (geo readout only makes sense for a slippy-map +// basemap, never a DZI pyramid), so they are pure and unit-testable. The underlying // projection (pixel↔lng/lat) is core's geometry/geo — this module only composes it over a note's shape. import { formatLngLat, parseFragmentXYWH, parsePolygonPoints, pixelToLngLat, - type AnnotationRecord, type W3CTarget, type GeoAnchor, type TileSourceDescriptor, + type AnnotationRecord, type W3CTarget, type GeoAnchor, type XyzTileSource, } from "@render/core"; /** The selector `value` string off a record's target (xywh / polygon fragment), or "" if absent. */ @@ -15,7 +16,7 @@ export const selectorValue = (r: AnnotationRecord): string => // Geo readout (geo-annotation, Q5): the region's CENTRE lng/lat. Prefer the stored geo-truth (archie:geo, // ADR-0015 — record.geo); fall back to deriving from the pixel selector for any pre-geo record. Returns // null off a Map (no tileSource) or when the shape can't be located. -export function geoLabelOf(r: AnnotationRecord, ts: TileSourceDescriptor | undefined): string | null { +export function geoLabelOf(r: AnnotationRecord, ts: XyzTileSource | undefined): string | null { if (!ts) return null; if (r.geo?.type === "bbox") return formatLngLat({ lng: (r.geo.west + r.geo.east) / 2, lat: (r.geo.south + r.geo.north) / 2 }); if (r.geo?.type === "polygon" && r.geo.coordinates.length) { @@ -29,7 +30,7 @@ export function geoLabelOf(r: AnnotationRecord, ts: TileSourceDescriptor | undef // Geo-truth capture (Q4 / ADR-0015): turn a drawn region's WORLD-pixel selector into its lng/lat anchor // (the source of truth). Box → bbox (NW/SE corners); Outline → polygon (each vertex). undefined off-map. -export function geoForTarget(target: W3CTarget, ts: TileSourceDescriptor | undefined): GeoAnchor | undefined { +export function geoForTarget(target: W3CTarget, ts: XyzTileSource | undefined): GeoAnchor | undefined { if (!ts) return undefined; const v = (target as { selector?: { value?: string } } | undefined)?.selector?.value; if (!v) return undefined; diff --git a/apps/studio/src/ingest-flows.ts b/apps/studio/src/ingest-flows.ts index d5c191c3..805d089f 100644 --- a/apps/studio/src/ingest-flows.ts +++ b/apps/studio/src/ingest-flows.ts @@ -10,7 +10,7 @@ import { AnnotationSession, loadLibrary, ZipFilesystem, libraryToWorking, mediaTypeFromSource, readExifOrientation, isOrientationNoop, orientationTransform, MAX_MASTER_DIM, readExifCaptureDate, - type Library, type ClientId, type TileSourceDescriptor, type W3CTextualBody, + type Library, type ClientId, type XyzTileSource, type W3CTextualBody, type WorkingObjectMeta as ObjectMeta, } from "@render/core"; import { bakeDisplayMaster, downscaleIfNeeded, bakeThumbnail } from "./bake.js"; @@ -120,7 +120,7 @@ export function createIngestFlows(ctx: IngestContext) { } // Add-map modal (Phase 3 / Q3 — invented UX, human-gated): a Map is an Object whose source is its tile // template and which carries the tileSource descriptor (medium = Map). The modal supplies template + bounds. - async function addMapObject(m: { label: string; tileSource: TileSourceDescriptor }) { + async function addMapObject(m: { label: string; tileSource: XyzTileSource }) { const ex = exhibit(); if (!ex) return; const id = nextObjectId(ex); diff --git a/apps/viewer/fixtures/geo.ts b/apps/viewer/fixtures/geo.ts index 46e00da5..d2e3562f 100644 --- a/apps/viewer/fixtures/geo.ts +++ b/apps/viewer/fixtures/geo.ts @@ -8,14 +8,14 @@ // ONLY here. Both the Studio (seed-data.ts → seededGeo / DEFAULT_EXHIBITS) and the Viewer's published library // (sample-data.ts → buildGeoLog) import this file; neither redefines the basemap or recomputes the pin // geometry, so the authored Studio seed and the published bake cannot drift. Mirrors voynich.ts / atlas.ts. -import { asObjectId, lngLatToPixel, pixelToLngLat, thumbnailUrl, type AObject, type RightsFields, type TileSourceDescriptor } from "@render/core"; +import { asObjectId, lngLatToPixel, pixelToLngLat, thumbnailUrl, type AObject, type RightsFields, type XyzTileSource } from "@render/core"; /** OSM raster XYZ template — `{z}/{x}/{y}` slippy tiles, fetched live. */ export const GEO_TEMPLATE = "https://tile.openstreetmap.org/{z}/{x}/{y}.png"; /** The basemap descriptor: whole-world Web-Mercator, maxZoom 6 (world→continent, light to demo). The full * pixel extent is tileSize·2^maxZoom = 256·2^6 = 16384px square — the coordinate frame every pin lives in. */ -export const geoBasemap: TileSourceDescriptor = { kind: "xyz", template: GEO_TEMPLATE, tileSize: 256, minZoom: 0, maxZoom: 6, attribution: "© OpenStreetMap contributors" }; +export const geoBasemap: XyzTileSource = { kind: "xyz", template: GEO_TEMPLATE, tileSize: 256, minZoom: 0, maxZoom: 6, attribution: "© OpenStreetMap contributors" }; /** The OSM tile usage policy REQUIRES attribution — surfaced as a credit on the Map canvas. */ export const geoRights: RightsFields = { rights: "https://opendatacommons.org/licenses/odbl/", requiredStatement: { label: "Basemap", value: "© OpenStreetMap contributors, ODbL." } }; From d8017be4fc87a067ad95f769ffe045e8f274a115 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:48:27 -0700 Subject: [PATCH 06/24] chore: remove accidentally-tracked --output shell-redirect residue Ledger ledgers/ARTIFACTS.md row 1. --- --output | 4036 ---------------------------------------------------- .gitignore | 5 + 2 files changed, 5 insertions(+), 4036 deletions(-) delete mode 100644 --output diff --git a/--output b/--output deleted file mode 100644 index bfeb7594..00000000 --- a/--output +++ /dev/null @@ -1,4036 +0,0 @@ -{ - "scriptCompleted": true, - "files": [ - { - "path": ".agents/skills/domain-modeling/ADR-FORMAT.md", - "language": "markdown", - "sizeLines": 47, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/domain-modeling/CONTEXT-FORMAT.md", - "language": "markdown", - "sizeLines": 60, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/domain-modeling/SKILL.md", - "language": "markdown", - "sizeLines": 74, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/teach/GLOSSARY-FORMAT.md", - "language": "markdown", - "sizeLines": 35, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/teach/LEARNING-RECORD-FORMAT.md", - "language": "markdown", - "sizeLines": 46, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/teach/MISSION-FORMAT.md", - "language": "markdown", - "sizeLines": 31, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/teach/MISSION.md", - "language": "markdown", - "sizeLines": 27, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/teach/RESOURCES-FORMAT.md", - "language": "markdown", - "sizeLines": 32, - "fileCategory": "docs" - }, - { - "path": ".agents/skills/teach/SKILL.md", - "language": "markdown", - "sizeLines": 140, - "fileCategory": "docs" - }, - { - "path": ".claude/.deps-index/pending.json", - "language": "json", - "sizeLines": 42, - "fileCategory": "config" - }, - { - "path": ".claude/.deps-index/resolved.json", - "language": "json", - "sizeLines": 137, - "fileCategory": "config" - }, - { - "path": ".claude/.skill-invocation-log", - "language": "unknown", - "sizeLines": 29, - "fileCategory": "code" - }, - { - "path": ".claude/goals/goal.md", - "language": "markdown", - "sizeLines": 74, - "fileCategory": "docs" - }, - { - "path": ".claude/rules/deps-index.md", - "language": "markdown", - "sizeLines": 38, - "fileCategory": "docs" - }, - { - "path": ".claude/settings.json", - "language": "json", - "sizeLines": 5, - "fileCategory": "config" - }, - { - "path": ".claude/skills/librarian/SKILL.md", - "language": "markdown", - "sizeLines": 194, - "fileCategory": "docs" - }, - { - "path": ".claude/skills/product-copy/SKILL.md", - "language": "markdown", - "sizeLines": 105, - "fileCategory": "docs" - }, - { - "path": ".claude/SUGGESTED_SKILLS.md", - "language": "markdown", - "sizeLines": 24, - "fileCategory": "docs" - }, - { - "path": ".gitattributes", - "language": "unknown", - "sizeLines": 4, - "fileCategory": "code" - }, - { - "path": ".github/workflows/deploy.yml", - "language": "yaml", - "sizeLines": 45, - "fileCategory": "infra" - }, - { - "path": ".interface-design/system.md", - "language": "markdown", - "sizeLines": 323, - "fileCategory": "docs" - }, - { - "path": ".mulch/decisions/archie-av.q-counter", - "language": "q-counter", - "sizeLines": 1, - "fileCategory": "code" - }, - { - "path": ".mulch/decisions/archie-linkability.q-counter", - "language": "q-counter", - "sizeLines": 1, - "fileCategory": "code" - }, - { - "path": ".mulch/decisions/archie-narrative.q-counter", - "language": "q-counter", - "sizeLines": 1, - "fileCategory": "code" - }, - { - "path": ".mulch/decisions/archie-persistence.q-counter", - "language": "q-counter", - "sizeLines": 1, - "fileCategory": "code" - }, - { - "path": ".mulch/decisions/archie-ux.q-counter", - "language": "q-counter", - "sizeLines": 1, - "fileCategory": "code" - }, - { - "path": ".mulch/decisions/archie.q-counter", - "language": "q-counter", - "sizeLines": 1, - "fileCategory": "code" - }, - { - "path": ".mulch/expertise/archie.jsonl", - "language": "jsonl", - "sizeLines": 4, - "fileCategory": "code" - }, - { - "path": ".mulch/expertise/architecture.jsonl", - "language": "jsonl", - "sizeLines": 5, - "fileCategory": "code" - }, - { - "path": ".mulch/expertise/decisions.jsonl", - "language": "jsonl", - "sizeLines": 48, - "fileCategory": "code" - }, - { - "path": ".mulch/expertise/infrastructure.jsonl", - "language": "jsonl", - "sizeLines": 14, - "fileCategory": "code" - }, - { - "path": ".mulch/expertise/meta.jsonl", - "language": "jsonl", - "sizeLines": 14, - "fileCategory": "code" - }, - { - "path": ".mulch/expertise/product-research.jsonl", - "language": "jsonl", - "sizeLines": 22, - "fileCategory": "code" - }, - { - "path": ".mulch/mulch.config.yaml", - "language": "yaml", - "sizeLines": 16, - "fileCategory": "config" - }, - { - "path": ".mulch/README.md", - "language": "markdown", - "sizeLines": 21, - "fileCategory": "docs" - }, - { - "path": ".seeds/config.yaml", - "language": "yaml", - "sizeLines": 2, - "fileCategory": "config" - }, - { - "path": ".seeds/issues.jsonl", - "language": "jsonl", - "sizeLines": 76, - "fileCategory": "code" - }, - { - "path": ".seeds/templates.jsonl", - "language": "jsonl", - "sizeLines": 0, - "fileCategory": "code" - }, - { - "path": ".understand-anything/.understandignore", - "language": "unknown", - "sizeLines": 23, - "fileCategory": "code" - }, - { - "path": ".understand-anything/domain-graph.json", - "language": "json", - "sizeLines": 894, - "fileCategory": "config" - }, - { - "path": ".understand-anything/fingerprints.json", - "language": "json", - "sizeLines": 8089, - "fileCategory": "config" - }, - { - "path": ".understand-anything/knowledge-graph.json", - "language": "json", - "sizeLines": 13882, - "fileCategory": "config" - }, - { - "path": ".understand-anything/meta.json", - "language": "json", - "sizeLines": 6, - "fileCategory": "config" - }, - { - "path": ".understand-anything/tmp/changed-files.txt", - "language": "txt", - "sizeLines": 693, - "fileCategory": "docs" - }, - { - "path": "anti-pattern-report.txt", - "language": "txt", - "sizeLines": 267, - "fileCategory": "docs" - }, - { - "path": "apps/studio/.gitkeep", - "language": "unknown", - "sizeLines": 0, - "fileCategory": "code" - }, - { - "path": "apps/studio/index.html", - "language": "html", - "sizeLines": 14, - "fileCategory": "markup" - }, - { - "path": "apps/studio/package.json", - "language": "json", - "sizeLines": 26, - "fileCategory": "config" - }, - { - "path": "apps/studio/public/fonts/fonts.css", - "language": "css", - "sizeLines": 9, - "fileCategory": "markup" - }, - { - "path": "apps/studio/public/fonts/VinqueAntique-Bold.otf", - "language": "otf", - "sizeLines": 481, - "fileCategory": "code" - }, - { - "path": "apps/studio/public/fonts/VinqueAntique-BoldItalic.otf", - "language": "otf", - "sizeLines": 554, - "fileCategory": "code" - }, - { - "path": "apps/studio/README.md", - "language": "markdown", - "sizeLines": 39, - "fileCategory": "docs" - }, - { - "path": "apps/studio/src/AddMapModal.svelte", - "language": "svelte", - "sizeLines": 236, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/App.svelte", - "language": "svelte", - "sizeLines": 2009, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/atmosphere.css", - "language": "css", - "sizeLines": 93, - "fileCategory": "markup" - }, - { - "path": "apps/studio/src/AvEditor.svelte", - "language": "svelte", - "sizeLines": 413, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/bake.ts", - "language": "typescript", - "sizeLines": 103, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/binding-store.svelte.ts", - "language": "typescript", - "sizeLines": 194, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/binding.test.ts", - "language": "typescript", - "sizeLines": 78, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/binding.ts", - "language": "typescript", - "sizeLines": 135, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/CmdK.svelte", - "language": "svelte", - "sizeLines": 167, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/collab.test.ts", - "language": "typescript", - "sizeLines": 42, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/collab.ts", - "language": "typescript", - "sizeLines": 38, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/csv-import.test.ts", - "language": "typescript", - "sizeLines": 177, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/csv-import.ts", - "language": "typescript", - "sizeLines": 187, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/DetailsEditor.svelte", - "language": "svelte", - "sizeLines": 94, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/exhibit-session.svelte.ts", - "language": "typescript", - "sizeLines": 141, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/ExhibitOverview.svelte", - "language": "svelte", - "sizeLines": 466, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/folder-import.test.ts", - "language": "typescript", - "sizeLines": 130, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/folder-import.ts", - "language": "typescript", - "sizeLines": 103, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/geo-notes.test.ts", - "language": "typescript", - "sizeLines": 56, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/geo-notes.ts", - "language": "typescript", - "sizeLines": 45, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/handles-db.ts", - "language": "typescript", - "sizeLines": 74, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/IdentityPrompt.svelte", - "language": "svelte", - "sizeLines": 71, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/iiif-import.test.ts", - "language": "typescript", - "sizeLines": 117, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/iiif-import.ts", - "language": "typescript", - "sizeLines": 125, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/ingest-flows.ts", - "language": "typescript", - "sizeLines": 465, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/library-meta-reducers.test.ts", - "language": "typescript", - "sizeLines": 78, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/library-meta-reducers.ts", - "language": "typescript", - "sizeLines": 52, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/library-meta.svelte.test.ts", - "language": "typescript", - "sizeLines": 77, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/library-meta.svelte.ts", - "language": "typescript", - "sizeLines": 67, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/LibraryHome.svelte", - "language": "svelte", - "sizeLines": 381, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/main.ts", - "language": "typescript", - "sizeLines": 13, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/markers.css", - "language": "css", - "sizeLines": 33, - "fileCategory": "markup" - }, - { - "path": "apps/studio/src/MediaPicker.svelte", - "language": "svelte", - "sizeLines": 110, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/MergeReview.svelte", - "language": "svelte", - "sizeLines": 97, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/narrative-cue-reducer.test.ts", - "language": "typescript", - "sizeLines": 43, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/narrative-cue-reducer.ts", - "language": "typescript", - "sizeLines": 34, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/NarrativeEditor.svelte", - "language": "svelte", - "sizeLines": 276, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/NoteEditor.svelte", - "language": "svelte", - "sizeLines": 138, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/PropsDrawer.svelte", - "language": "svelte", - "sizeLines": 45, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/publish-flows.svelte.ts", - "language": "typescript", - "sizeLines": 172, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/Publish.svelte", - "language": "svelte", - "sizeLines": 213, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/PublishDialog.svelte", - "language": "svelte", - "sizeLines": 260, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/reading-state.svelte.test.ts", - "language": "typescript", - "sizeLines": 96, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/reading-state.svelte.ts", - "language": "typescript", - "sizeLines": 64, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/ReadingsEditor.svelte", - "language": "svelte", - "sizeLines": 105, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/ReadingsModal.svelte", - "language": "svelte", - "sizeLines": 71, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/ReadingsRail.svelte", - "language": "svelte", - "sizeLines": 87, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/RightsEditor.svelte", - "language": "svelte", - "sizeLines": 85, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/save-queue.svelte.test.ts", - "language": "typescript", - "sizeLines": 78, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/save-queue.svelte.ts", - "language": "typescript", - "sizeLines": 71, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/seed-data.ts", - "language": "typescript", - "sizeLines": 145, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/shortcuts.ts", - "language": "typescript", - "sizeLines": 56, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/ShortcutsHelp.svelte", - "language": "svelte", - "sizeLines": 64, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/store.ts", - "language": "typescript", - "sizeLines": 329, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/tokens.css", - "language": "css", - "sizeLines": 122, - "fileCategory": "markup" - }, - { - "path": "apps/studio/src/wadm-import.test.ts", - "language": "typescript", - "sizeLines": 83, - "fileCategory": "code" - }, - { - "path": "apps/studio/src/wadm-import.ts", - "language": "typescript", - "sizeLines": 127, - "fileCategory": "code" - }, - { - "path": "apps/studio/vite.config.ts", - "language": "typescript", - "sizeLines": 38, - "fileCategory": "code" - }, - { - "path": "apps/studio/vitest.config.ts", - "language": "typescript", - "sizeLines": 14, - "fileCategory": "code" - }, - { - "path": "apps/viewer/astro.config.mjs", - "language": "javascript", - "sizeLines": 30, - "fileCategory": "code" - }, - { - "path": "apps/viewer/fixtures/atlas.ts", - "language": "typescript", - "sizeLines": 109, - "fileCategory": "code" - }, - { - "path": "apps/viewer/fixtures/geo.ts", - "language": "typescript", - "sizeLines": 58, - "fileCategory": "code" - }, - { - "path": "apps/viewer/fixtures/sample-data.ts", - "language": "typescript", - "sizeLines": 198, - "fileCategory": "code" - }, - { - "path": "apps/viewer/fixtures/voynich.ts", - "language": "typescript", - "sizeLines": 214, - "fileCategory": "code" - }, - { - "path": "apps/viewer/libraries/README.md", - "language": "markdown", - "sizeLines": 23, - "fileCategory": "docs" - }, - { - "path": "apps/viewer/package.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/fonts/fonts.css", - "language": "css", - "sizeLines": 9, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/fonts/VinqueAntique-Bold.otf", - "language": "otf", - "sizeLines": 481, - "fileCategory": "code" - }, - { - "path": "apps/viewer/public/fonts/VinqueAntique-BoldItalic.otf", - "language": "otf", - "sizeLines": 554, - "fileCategory": "code" - }, - { - "path": "apps/viewer/public/published/collection.json", - "language": "json", - "sizeLines": 91, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/exhibits.json", - "language": "json", - "sizeLines": 45, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/annotations/history/0000000001Q1E2RFF58H62PFSW.json", - "language": "json", - "sizeLines": 40, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/annotations/history/0000000002Q00FVKNSJJ2BGTDE.json", - "language": "json", - "sizeLines": 40, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/annotations/history/00000000032HVBH9EHJCR5YMRR.json", - "language": "json", - "sizeLines": 40, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/annotations/history/0000000004CK4MH8W1V2DW0N39.json", - "language": "json", - "sizeLines": 40, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/annotations/history/index.json", - "language": "json", - "sizeLines": 5, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/canvas/m1/annotations.json", - "language": "json", - "sizeLines": 126, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/geo-map/index.html", - "language": "html", - "sizeLines": 34, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/published/geo-map/manifest.json", - "language": "json", - "sizeLines": 204, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/index.html", - "language": "html", - "sizeLines": 22, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/0000000001QA9HWMFBS3S6DTJ4.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/00000000021G31YS0Z2ZG6N1RX.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/0000000003EB0YAESVXD6MKPY6.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/0000000004P0QSM9AM36QZM3JY.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/00000000056XKG648T6Z7TAAQX.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000689W361NNJSBV1NNV.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/00000000073MHG0BGX4NK51FTH.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/0000000008DGND2JNBFKR1YW4B.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/00000000093KM2FAXA5WQDQ82Q.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000AN029WSZ324T8AK3J.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000BTCT9T76FKBHTEJK4.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000C36QGH1EA6FN8ZNXN.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000D9Z2PS1FE0YRQNX28.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000EHP928C5GZ7MJ1KGS.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000FV4ZR6350WQCQE3BN.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000GK82XFVPQDZNMX4KC.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000HDQ0N6DX74Q43Q9SG.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000JTC0PHRKF5DWSN6JR.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000KRK6BRR71P6PX20V0.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000MG36QD4YX5V1YJ8HW.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000NXQ7R2V1N9674N2QK.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000PZN8JWP0A1HSVXMJM.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000QRY7P4XVEGX7X1XCA.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/000000000R8Y311HDC71SWDHVT.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/history/index.json", - "language": "json", - "sizeLines": 25, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/readings/community.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/annotations/readings/linguist.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o1/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o1/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o1/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o2/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o2/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o2/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o3/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o3/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o3/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o4/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o4/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o4/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o5/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o5/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o5/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o6/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o6/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o6/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o7/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o7/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o7/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o8/annotations-community.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o8/annotations-linguist.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/canvas/o8/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/index.html", - "language": "html", - "sizeLines": 137, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/published/language-atlas/manifest.json", - "language": "json", - "sizeLines": 1508, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/language-atlas/readings.json", - "language": "json", - "sizeLines": 13, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/sitemap.txt", - "language": "txt", - "sizeLines": 6, - "fileCategory": "docs" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000001M0GZY8KQDZEF4C74.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000002QERZ7R4AD74QJ481.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000003V9WGXP5NY4Z5C3CA.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000004429NM3GG6S8ZYV05.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000005W9XVMN7C968XY5A2.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000616MM0ADVMBBK0XHJ.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000007GCR82ZZ0V3CKGCP4.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000008MSMNY0VX0THJB32N.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000009P1SYAXVMEKD64YM1.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000AZ5MWJJCKJSVCRP75.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000BQ1719XADN4MSNF3D.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000CGES9SXD5HHBYMGF1.json", - "language": "json", - "sizeLines": 54, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000D5SH6F04BJZCKGCC2.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000EBTVCRTK515MFGEAM.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000FQ49APBGFAPPZ2Z93.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000GD9N71MHZSCFJM2MB.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000HTMR0MJ171Q2W6C1M.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000JV4R2HB536DH4YA1E.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000KN9BECJFQPP1EDDVP.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000M8K248PTFFZR2Y36H.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000NSFASYX2TFC4DE7GZ.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000PHK5Q5G86C31C1M59.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000Q47KB1X12V54QJQ7N.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000RPZP2N8FCZGDY2CSY.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000SPZ8YDM9SEQKNS8A9.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000T5N0B9CP2EE6P6Z5W.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000VJPMVWXVNE66V47J0.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000W8BQMN0WT7K65A25J.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000XAGKZA0P14VWSNZ0Q.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000YTTF352G3HGS6SAGC.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000000ZKTQFJWBE5DHG6CEX.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/00000000103N8G97G375T4RR47.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000011YTBN4W131SCZKA7M.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000012RSQD9VZQ7601ZAA6.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000013E2ZHQMTVKKYX844Z.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000014RM3WBR0S55GK9QKA.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000015XBMQ294BD4FB74XX.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000016PE2QB9MW3RR9FE5K.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/00000000174012M3JVECQ4CWZJ.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001876WEDG0CY9Q9PFNG.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/0000000019PGCFHGFQM3XPC4YF.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001AYSHEDSMARM8NK98D.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001BASS5X8QB9YS79JAD.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001C9W0J2BKMJA125KR2.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001DKSXRNKR02TMX11VZ.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001EM5QNPFCQ5A2K3W6H.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001FHXMQBYHST49K7EYG.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/000000001G39GVAR3H0FA56RD5.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/history/index.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/narrative.json", - "language": "json", - "sizeLines": 182, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/readings/abjad.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/readings/cipher.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/annotations/readings/hoax.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o1/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o1/annotations-cipher.json", - "language": "json", - "sizeLines": 56, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o1/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o1/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o10/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o10/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o10/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o10/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o11/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o11/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o11/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o11/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o12/annotations-abjad.json", - "language": "json", - "sizeLines": 11, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o12/annotations-cipher.json", - "language": "json", - "sizeLines": 11, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o12/annotations-hoax.json", - "language": "json", - "sizeLines": 11, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o12/annotations.json", - "language": "json", - "sizeLines": 98, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o2/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o2/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o2/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o2/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o3/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o3/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o3/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o3/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o4/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o4/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o4/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o4/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o5/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o5/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o5/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o5/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o6/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o6/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o6/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o6/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o7/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o7/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o7/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o7/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o8/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o8/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o8/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o8/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o9/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o9/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o9/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/canvas/o9/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/index.html", - "language": "html", - "sizeLines": 265, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/published/voynich-reading/manifest.json", - "language": "json", - "sizeLines": 3085, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-reading/readings.json", - "language": "json", - "sizeLines": 19, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/history/0000000001M0GZY8KQDZEF4C74.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/history/0000000002QERZ7R4AD74QJ481.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/history/0000000003V9WGXP5NY4Z5C3CA.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/history/0000000004429NM3GG6S8ZYV05.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/history/index.json", - "language": "json", - "sizeLines": 5, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/readings/abjad.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/readings/cipher.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/annotations/readings/hoax.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/canvas/o9/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/canvas/o9/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/canvas/o9/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/canvas/o9/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/index.html", - "language": "html", - "sizeLines": 38, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/manifest.json", - "language": "json", - "sizeLines": 274, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich-rosettes/readings.json", - "language": "json", - "sizeLines": 19, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000001M0GZY8KQDZEF4C74.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000002QERZ7R4AD74QJ481.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000003V9WGXP5NY4Z5C3CA.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000004429NM3GG6S8ZYV05.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000005W9XVMN7C968XY5A2.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000616MM0ADVMBBK0XHJ.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000007GCR82ZZ0V3CKGCP4.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000008MSMNY0VX0THJB32N.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000009P1SYAXVMEKD64YM1.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000AZ5MWJJCKJSVCRP75.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000BQ1719XADN4MSNF3D.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000CGES9SXD5HHBYMGF1.json", - "language": "json", - "sizeLines": 54, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000D5SH6F04BJZCKGCC2.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000EBTVCRTK515MFGEAM.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000FQ49APBGFAPPZ2Z93.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000GD9N71MHZSCFJM2MB.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000HTMR0MJ171Q2W6C1M.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000JV4R2HB536DH4YA1E.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000KN9BECJFQPP1EDDVP.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000M8K248PTFFZR2Y36H.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000NSFASYX2TFC4DE7GZ.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000PHK5Q5G86C31C1M59.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000Q47KB1X12V54QJQ7N.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000RPZP2N8FCZGDY2CSY.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000SPZ8YDM9SEQKNS8A9.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000T5N0B9CP2EE6P6Z5W.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000VJPMVWXVNE66V47J0.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000W8BQMN0WT7K65A25J.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000XAGKZA0P14VWSNZ0Q.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000YTTF352G3HGS6SAGC.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000000ZKTQFJWBE5DHG6CEX.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/00000000103N8G97G375T4RR47.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000011YTBN4W131SCZKA7M.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000012RSQD9VZQ7601ZAA6.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000013E2ZHQMTVKKYX844Z.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000014RM3WBR0S55GK9QKA.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000015XBMQ294BD4FB74XX.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000016PE2QB9MW3RR9FE5K.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/00000000174012M3JVECQ4CWZJ.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001876WEDG0CY9Q9PFNG.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/0000000019PGCFHGFQM3XPC4YF.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001AYSHEDSMARM8NK98D.json", - "language": "json", - "sizeLines": 44, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001BASS5X8QB9YS79JAD.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001C9W0J2BKMJA125KR2.json", - "language": "json", - "sizeLines": 34, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001DKSXRNKR02TMX11VZ.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001EM5QNPFCQ5A2K3W6H.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001FHXMQBYHST49K7EYG.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/000000001G39GVAR3H0FA56RD5.json", - "language": "json", - "sizeLines": 33, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/history/index.json", - "language": "json", - "sizeLines": 49, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/readings/abjad.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/readings/cipher.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/annotations/readings/hoax.json", - "language": "json", - "sizeLines": 14, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o1/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o1/annotations-cipher.json", - "language": "json", - "sizeLines": 56, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o1/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o1/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o10/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o10/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o10/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o10/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o11/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o11/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o11/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o11/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o12/annotations-abjad.json", - "language": "json", - "sizeLines": 11, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o12/annotations-cipher.json", - "language": "json", - "sizeLines": 11, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o12/annotations-hoax.json", - "language": "json", - "sizeLines": 11, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o12/annotations.json", - "language": "json", - "sizeLines": 98, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o2/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o2/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o2/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o2/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o3/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o3/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o3/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o3/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o4/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o4/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o4/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o4/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o5/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o5/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o5/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o5/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o6/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o6/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o6/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o6/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o7/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o7/annotations-cipher.json", - "language": "json", - "sizeLines": 46, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o7/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o7/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o8/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o8/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o8/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o8/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o9/annotations-abjad.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o9/annotations-cipher.json", - "language": "json", - "sizeLines": 51, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o9/annotations-hoax.json", - "language": "json", - "sizeLines": 36, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/canvas/o9/annotations.json", - "language": "json", - "sizeLines": 29, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/index.html", - "language": "html", - "sizeLines": 265, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/public/published/voynich/manifest.json", - "language": "json", - "sizeLines": 2915, - "fileCategory": "config" - }, - { - "path": "apps/viewer/public/published/voynich/readings.json", - "language": "json", - "sizeLines": 19, - "fileCategory": "config" - }, - { - "path": "apps/viewer/README.md", - "language": "markdown", - "sizeLines": 43, - "fileCategory": "docs" - }, - { - "path": "apps/viewer/scripts/gen-published.mts", - "language": "mts", - "sizeLines": 134, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/aside-persistence.ts", - "language": "typescript", - "sizeLines": 39, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/atmosphere.css", - "language": "css", - "sizeLines": 93, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/src/cite-cards.test.ts", - "language": "typescript", - "sizeLines": 41, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/cite-cards.ts", - "language": "typescript", - "sizeLines": 34, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/cite-context.ts", - "language": "typescript", - "sizeLines": 12, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/Credit.svelte", - "language": "svelte", - "sizeLines": 61, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/EmptyHall.svelte", - "language": "svelte", - "sizeLines": 163, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ExhibitCiteCard.svelte", - "language": "svelte", - "sizeLines": 47, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ExhibitView.svelte", - "language": "svelte", - "sizeLines": 409, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/Gallery.svelte", - "language": "svelte", - "sizeLines": 76, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/MediaPlayer.svelte", - "language": "svelte", - "sizeLines": 263, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/MediaThumbnail.svelte", - "language": "svelte", - "sizeLines": 93, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/narrative-escape.test.ts", - "language": "typescript", - "sizeLines": 100, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/NarrativeReader.svelte", - "language": "svelte", - "sizeLines": 316, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/NoteLightbox.svelte", - "language": "svelte", - "sizeLines": 117, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/NoteMedia.svelte", - "language": "svelte", - "sizeLines": 66, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ObjectGrid.svelte", - "language": "svelte", - "sizeLines": 96, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ProseCites.svelte", - "language": "svelte", - "sizeLines": 20, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/Reader.svelte", - "language": "svelte", - "sizeLines": 345, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ReadingLegend.svelte", - "language": "svelte", - "sizeLines": 105, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ReadingSheet.svelte", - "language": "svelte", - "sizeLines": 51, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/SidebarObjectNav.svelte", - "language": "svelte", - "sizeLines": 87, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/components/ViewerShell.svelte", - "language": "svelte", - "sizeLines": 383, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/markers.css", - "language": "css", - "sizeLines": 33, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/src/og-image.ts", - "language": "typescript", - "sizeLines": 16, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/pages/[slug].astro", - "language": "astro", - "sizeLines": 122, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/pages/index.astro", - "language": "astro", - "sizeLines": 44, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/pages/robots.txt.ts", - "language": "typescript", - "sizeLines": 7, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/pages/sitemap.xml.ts", - "language": "typescript", - "sizeLines": 12, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/published-base.ts", - "language": "typescript", - "sizeLines": 32, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/published.test.ts", - "language": "typescript", - "sizeLines": 169, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/published.ts", - "language": "typescript", - "sizeLines": 290, - "fileCategory": "code" - }, - { - "path": "apps/viewer/src/tokens.css", - "language": "css", - "sizeLines": 143, - "fileCategory": "markup" - }, - { - "path": "apps/viewer/tsconfig.json", - "language": "json", - "sizeLines": 9, - "fileCategory": "config" - }, - { - "path": "archie.config.json", - "language": "json", - "sizeLines": 6, - "fileCategory": "config" - }, - { - "path": "CLAUDE.md", - "language": "markdown", - "sizeLines": 62, - "fileCategory": "docs" - }, - { - "path": "design/fonts/licenses/FOPVHS - font by lirkiv.txt", - "language": "txt", - "sizeLines": 11, - "fileCategory": "docs" - }, - { - "path": "design/fonts/licenses/License LARAZ Font.txt", - "language": "txt", - "sizeLines": 2, - "fileCategory": "docs" - }, - { - "path": "design/fonts/VinqueAntique-Bold.otf", - "language": "otf", - "sizeLines": 481, - "fileCategory": "code" - }, - { - "path": "design/fonts/VinqueAntique-BoldItalic.otf", - "language": "otf", - "sizeLines": 554, - "fileCategory": "code" - }, - { - "path": "docs/adr/0001-objects-are-exhibit-nested.md", - "language": "markdown", - "sizeLines": 23, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0002-rendering-and-framework.md", - "language": "markdown", - "sizeLines": 25, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0003-annotation-spine-append-only-version-dag.md", - "language": "markdown", - "sizeLines": 41, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0004-no-wasm-vips-tiling.md", - "language": "markdown", - "sizeLines": 10, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0005-narrative-section-model.md", - "language": "markdown", - "sizeLines": 17, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0006-edit-at-locus-spatiotemporal-selectors.md", - "language": "markdown", - "sizeLines": 79, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0007-readings-as-annotationpages.md", - "language": "markdown", - "sizeLines": 31, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0008-viewer-one-shell-dual-mode.md", - "language": "markdown", - "sizeLines": 15, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0009-canonical-hosted-instance-for-src.md", - "language": "markdown", - "sizeLines": 19, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0010-portable-viewer-read-seam.md", - "language": "markdown", - "sizeLines": 22, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0011-gesture-initiated-creation.md", - "language": "markdown", - "sizeLines": 71, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0012-self-hosted-fonts.md", - "language": "markdown", - "sizeLines": 31, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0013-canonical-origin-github-pages.md", - "language": "markdown", - "sizeLines": 35, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0014-self-describing-published-artifact.md", - "language": "markdown", - "sizeLines": 48, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0015-map-medium-bounded-extent.md", - "language": "markdown", - "sizeLines": 16, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0016-narrative-as-emergent-reading-mode.md", - "language": "markdown", - "sizeLines": 49, - "fileCategory": "docs" - }, - { - "path": "docs/adr/0017-section-as-supplementing-annotation.md", - "language": "markdown", - "sizeLines": 42, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/_meta.json", - "language": "json", - "sizeLines": 45, - "fileCategory": "config" - }, - { - "path": "docs/architecture/cross-cutting/patterns.md", - "language": "markdown", - "sizeLines": 88, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/domain.md", - "language": "markdown", - "sizeLines": 63, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/ecosystem.md", - "language": "markdown", - "sizeLines": 71, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/evolution.md", - "language": "markdown", - "sizeLines": 74, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/features.json", - "language": "json", - "sizeLines": 40, - "fileCategory": "config" - }, - { - "path": "docs/architecture/infrastructure.md", - "language": "markdown", - "sizeLines": 86, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/overview.md", - "language": "markdown", - "sizeLines": 101, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/risk-map.md", - "language": "markdown", - "sizeLines": 55, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems.md", - "language": "markdown", - "sizeLines": 99, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/annotation-spine/components.md", - "language": "markdown", - "sizeLines": 91, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/annotation-spine/contracts.md", - "language": "markdown", - "sizeLines": 81, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/publish/AUDIT-gh-publish.md", - "language": "markdown", - "sizeLines": 78, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/publish/components.md", - "language": "markdown", - "sizeLines": 61, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/publish/contracts.md", - "language": "markdown", - "sizeLines": 76, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/rendering/components.md", - "language": "markdown", - "sizeLines": 104, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/rendering/contracts.md", - "language": "markdown", - "sizeLines": 56, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/storage/components.md", - "language": "markdown", - "sizeLines": 53, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/storage/contracts.md", - "language": "markdown", - "sizeLines": 83, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/studio/components.md", - "language": "markdown", - "sizeLines": 76, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/studio/contracts.md", - "language": "markdown", - "sizeLines": 82, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/viewer/components.md", - "language": "markdown", - "sizeLines": 82, - "fileCategory": "docs" - }, - { - "path": "docs/architecture/subsystems/viewer/contracts.md", - "language": "markdown", - "sizeLines": 86, - "fileCategory": "docs" - }, - { - "path": "docs/bundle-size.json", - "language": "json", - "sizeLines": 31, - "fileCategory": "config" - }, - { - "path": "docs/decisions/archie-av.md", - "language": "markdown", - "sizeLines": 15, - "fileCategory": "docs" - }, - { - "path": "docs/decisions/archie-linkability.md", - "language": "markdown", - "sizeLines": 15, - "fileCategory": "docs" - }, - { - "path": "docs/decisions/archie-narrative.md", - "language": "markdown", - "sizeLines": 15, - "fileCategory": "docs" - }, - { - "path": "docs/decisions/archie-persistence.md", - "language": "markdown", - "sizeLines": 16, - "fileCategory": "docs" - }, - { - "path": "docs/decisions/archie-ux.md", - "language": "markdown", - "sizeLines": 15, - "fileCategory": "docs" - }, - { - "path": "docs/decisions/archie.md", - "language": "markdown", - "sizeLines": 20, - "fileCategory": "docs" - }, - { - "path": "docs/decisions/PROPOSALS.md", - "language": "markdown", - "sizeLines": 107, - "fileCategory": "docs" - }, - { - "path": "docs/GOAL.md", - "language": "markdown", - "sizeLines": 248, - "fileCategory": "docs" - }, - { - "path": "docs/IMPLEMENTATION-STRATEGY.md", - "language": "markdown", - "sizeLines": 307, - "fileCategory": "docs" - }, - { - "path": "docs/screenshots/auto/manifest.json", - "language": "json", - "sizeLines": 57, - "fileCategory": "config" - }, - { - "path": "package.json", - "language": "json", - "sizeLines": 23, - "fileCategory": "config" - }, - { - "path": "packages/render-core/package.json", - "language": "json", - "sizeLines": 23, - "fileCategory": "config" - }, - { - "path": "packages/render-core/src/av/time.test.ts", - "language": "typescript", - "sizeLines": 69, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/av/time.ts", - "language": "typescript", - "sizeLines": 71, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/av/transcript.test.ts", - "language": "typescript", - "sizeLines": 73, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/av/transcript.ts", - "language": "typescript", - "sizeLines": 103, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/exif/orientation.test.ts", - "language": "typescript", - "sizeLines": 51, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/exif/orientation.ts", - "language": "typescript", - "sizeLines": 46, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/exif/read.test.ts", - "language": "typescript", - "sizeLines": 142, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/exif/read.ts", - "language": "typescript", - "sizeLines": 148, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/binding.test.ts", - "language": "typescript", - "sizeLines": 98, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/binding.ts", - "language": "typescript", - "sizeLines": 109, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/conformance.test.ts", - "language": "typescript", - "sizeLines": 8, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/conformance.ts", - "language": "typescript", - "sizeLines": 96, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/fsa.ts", - "language": "typescript", - "sizeLines": 50, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/memory.ts", - "language": "typescript", - "sizeLines": 71, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/seam.test.ts", - "language": "typescript", - "sizeLines": 97, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/seam.ts", - "language": "typescript", - "sizeLines": 40, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/zip.streaming.test.ts", - "language": "typescript", - "sizeLines": 159, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/zip.test.ts", - "language": "typescript", - "sizeLines": 67, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/fs/zip.ts", - "language": "typescript", - "sizeLines": 156, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/coverage.test.ts", - "language": "typescript", - "sizeLines": 101, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/coverage.ts", - "language": "typescript", - "sizeLines": 59, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/downscale.test.ts", - "language": "typescript", - "sizeLines": 75, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/downscale.ts", - "language": "typescript", - "sizeLines": 23, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/geo.test.ts", - "language": "typescript", - "sizeLines": 133, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/geo.ts", - "language": "typescript", - "sizeLines": 127, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/marginalia.test.ts", - "language": "typescript", - "sizeLines": 137, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/marginalia.ts", - "language": "typescript", - "sizeLines": 134, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/mediafragment.test.ts", - "language": "typescript", - "sizeLines": 88, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/mediafragment.ts", - "language": "typescript", - "sizeLines": 77, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/panel-resize.test.ts", - "language": "typescript", - "sizeLines": 65, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/panel-resize.ts", - "language": "typescript", - "sizeLines": 41, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/selector.test.ts", - "language": "typescript", - "sizeLines": 109, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/geometry/selector.ts", - "language": "typescript", - "sizeLines": 128, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/canvasid.test.ts", - "language": "typescript", - "sizeLines": 41, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/canvasid.ts", - "language": "typescript", - "sizeLines": 16, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/collection.ts", - "language": "typescript", - "sizeLines": 29, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/exhibits.ts", - "language": "typescript", - "sizeLines": 89, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/gallery.test.ts", - "language": "typescript", - "sizeLines": 91, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/manifest-geo.test.ts", - "language": "typescript", - "sizeLines": 43, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/manifest.test.ts", - "language": "typescript", - "sizeLines": 187, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/manifest.ts", - "language": "typescript", - "sizeLines": 369, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/presentation.ts", - "language": "typescript", - "sizeLines": 148, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/resolve.test.ts", - "language": "typescript", - "sizeLines": 74, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/resolve.ts", - "language": "typescript", - "sizeLines": 102, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/rights.test.ts", - "language": "typescript", - "sizeLines": 191, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/iiif/rights.ts", - "language": "typescript", - "sizeLines": 85, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/index.test.ts", - "language": "typescript", - "sizeLines": 8, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/index.ts", - "language": "typescript", - "sizeLines": 87, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/link/link.test.ts", - "language": "typescript", - "sizeLines": 155, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/link/link.ts", - "language": "typescript", - "sizeLines": 202, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/migrate/migrate.test.ts", - "language": "typescript", - "sizeLines": 51, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/migrate/migrate.ts", - "language": "typescript", - "sizeLines": 89, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/model/layout.test.ts", - "language": "typescript", - "sizeLines": 43, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/model/layout.ts", - "language": "typescript", - "sizeLines": 36, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/model/library.test.ts", - "language": "typescript", - "sizeLines": 31, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/model/model.test.ts", - "language": "typescript", - "sizeLines": 42, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/model/model.ts", - "language": "typescript", - "sizeLines": 195, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/note/media.test.ts", - "language": "typescript", - "sizeLines": 52, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/note/media.ts", - "language": "typescript", - "sizeLines": 73, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/__snapshots__/voynich-readings.test.ts.snap", - "language": "snap", - "sizeLines": 234, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/ghpages.test.ts", - "language": "typescript", - "sizeLines": 159, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/ghpages.ts", - "language": "typescript", - "sizeLines": 209, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/interop.test.ts", - "language": "typescript", - "sizeLines": 102, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/merge.test.ts", - "language": "typescript", - "sizeLines": 53, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/merge.ts", - "language": "typescript", - "sizeLines": 64, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/portable.test.ts", - "language": "typescript", - "sizeLines": 200, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/portable.ts", - "language": "typescript", - "sizeLines": 188, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/preview.test.ts", - "language": "typescript", - "sizeLines": 86, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/read.test.ts", - "language": "typescript", - "sizeLines": 110, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/read.ts", - "language": "typescript", - "sizeLines": 103, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/site-geo.test.ts", - "language": "typescript", - "sizeLines": 45, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/site.test.ts", - "language": "typescript", - "sizeLines": 286, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/site.ts", - "language": "typescript", - "sizeLines": 420, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/static-pages.test.ts", - "language": "typescript", - "sizeLines": 155, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/static-pages.ts", - "language": "typescript", - "sizeLines": 125, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/voynich-readings.test.ts", - "language": "typescript", - "sizeLines": 125, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/working.test.ts", - "language": "typescript", - "sizeLines": 159, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/publish/working.ts", - "language": "typescript", - "sizeLines": 275, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/body.ts", - "language": "typescript", - "sizeLines": 10, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/filter.test.ts", - "language": "typescript", - "sizeLines": 44, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/filter.ts", - "language": "typescript", - "sizeLines": 54, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/marker-style.test.ts", - "language": "typescript", - "sizeLines": 64, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/marker-style.ts", - "language": "typescript", - "sizeLines": 45, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/published.test.ts", - "language": "typescript", - "sizeLines": 76, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/published.ts", - "language": "typescript", - "sizeLines": 105, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/query/reading.test.ts", - "language": "typescript", - "sizeLines": 187, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/session/session.test.ts", - "language": "typescript", - "sizeLines": 188, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/session/session.ts", - "language": "typescript", - "sizeLines": 237, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/deserialize.test.ts", - "language": "typescript", - "sizeLines": 130, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/deserialize.ts", - "language": "typescript", - "sizeLines": 110, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/geo-persist.test.ts", - "language": "typescript", - "sizeLines": 62, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/heads.test.ts", - "language": "typescript", - "sizeLines": 72, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/heads.ts", - "language": "typescript", - "sizeLines": 33, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/index.ts", - "language": "typescript", - "sizeLines": 8, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/interop.test.ts", - "language": "typescript", - "sizeLines": 115, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/log.test.ts", - "language": "typescript", - "sizeLines": 121, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/log.ts", - "language": "typescript", - "sizeLines": 172, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/merge.test.ts", - "language": "typescript", - "sizeLines": 141, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/merge.ts", - "language": "typescript", - "sizeLines": 218, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/persist.test.ts", - "language": "typescript", - "sizeLines": 110, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/persist.ts", - "language": "typescript", - "sizeLines": 72, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/resolve.test.ts", - "language": "typescript", - "sizeLines": 62, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/serialize.test.ts", - "language": "typescript", - "sizeLines": 140, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/spine/serialize.ts", - "language": "typescript", - "sizeLines": 236, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/text/sanitize.test.ts", - "language": "typescript", - "sizeLines": 74, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/text/sanitize.ts", - "language": "typescript", - "sizeLines": 45, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/url/breadcrumb.test.ts", - "language": "typescript", - "sizeLines": 37, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/url/breadcrumb.ts", - "language": "typescript", - "sizeLines": 43, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/url/deeplink.test.ts", - "language": "typescript", - "sizeLines": 52, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/url/deeplink.ts", - "language": "typescript", - "sizeLines": 90, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/url/route.test.ts", - "language": "typescript", - "sizeLines": 99, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/url/route.ts", - "language": "typescript", - "sizeLines": 64, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/wadm/brand.test.ts", - "language": "typescript", - "sizeLines": 81, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/wadm/brand.ts", - "language": "typescript", - "sizeLines": 144, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/wadm/index.ts", - "language": "typescript", - "sizeLines": 3, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/wadm/types.test.ts", - "language": "typescript", - "sizeLines": 116, - "fileCategory": "code" - }, - { - "path": "packages/render-core/src/wadm/types.ts", - "language": "typescript", - "sizeLines": 248, - "fileCategory": "code" - }, - { - "path": "packages/render-core/test/fixtures/exif/manifest.json", - "language": "json", - "sizeLines": 18, - "fileCategory": "config" - }, - { - "path": "packages/render-core/test/fixtures/exif/README.md", - "language": "markdown", - "sizeLines": 25, - "fileCategory": "docs" - }, - { - "path": "packages/render-core/tsconfig.json", - "language": "json", - "sizeLines": 8, - "fileCategory": "config" - }, - { - "path": "packages/render-mount/package.json", - "language": "json", - "sizeLines": 25, - "fileCategory": "config" - }, - { - "path": "packages/render-mount/src/fitbounds.test.ts", - "language": "typescript", - "sizeLines": 127, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/fitbounds.ts", - "language": "typescript", - "sizeLines": 110, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/frame-overlay.ts", - "language": "typescript", - "sizeLines": 95, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/gate.test.ts", - "language": "typescript", - "sizeLines": 61, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/gesture-guard.test.ts", - "language": "typescript", - "sizeLines": 51, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/gesture-guard.ts", - "language": "typescript", - "sizeLines": 44, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/index.test.ts", - "language": "typescript", - "sizeLines": 17, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/index.ts", - "language": "typescript", - "sizeLines": 17, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/mount-guard.test.ts", - "language": "typescript", - "sizeLines": 60, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/mount.ts", - "language": "typescript", - "sizeLines": 352, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/surface.ts", - "language": "typescript", - "sizeLines": 77, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/xyz.test.ts", - "language": "typescript", - "sizeLines": 27, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/xyz.ts", - "language": "typescript", - "sizeLines": 34, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/zoom-band.test.ts", - "language": "typescript", - "sizeLines": 22, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/src/zoom-band.ts", - "language": "typescript", - "sizeLines": 13, - "fileCategory": "code" - }, - { - "path": "packages/render-mount/tsconfig.json", - "language": "json", - "sizeLines": 8, - "fileCategory": "config" - }, - { - "path": "packages/render-mount/vitest.config.ts", - "language": "typescript", - "sizeLines": 11, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/package.json", - "language": "json", - "sizeLines": 30, - "fileCategory": "config" - }, - { - "path": "packages/render-svelte/src/Canvas.svelte", - "language": "svelte", - "sizeLines": 184, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/src/controller.test.ts", - "language": "typescript", - "sizeLines": 108, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/src/controller.ts", - "language": "typescript", - "sizeLines": 64, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/src/index.ts", - "language": "typescript", - "sizeLines": 13, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/src/MarginColumn.svelte", - "language": "svelte", - "sizeLines": 138, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/src/ResizeDivider.svelte", - "language": "svelte", - "sizeLines": 172, - "fileCategory": "code" - }, - { - "path": "packages/render-svelte/tsconfig.json", - "language": "json", - "sizeLines": 8, - "fileCategory": "config" - }, - { - "path": "pnpm-workspace.yaml", - "language": "yaml", - "sizeLines": 18, - "fileCategory": "config" - }, - { - "path": "README.md", - "language": "markdown", - "sizeLines": 341, - "fileCategory": "docs" - }, - { - "path": "scripts/build-gh-pages.sh", - "language": "shell", - "sizeLines": 79, - "fileCategory": "script" - }, - { - "path": "scripts/bundle-size.mjs", - "language": "javascript", - "sizeLines": 84, - "fileCategory": "code" - }, - { - "path": "scripts/capture-screenshots.mjs", - "language": "javascript", - "sizeLines": 170, - "fileCategory": "code" - }, - { - "path": "scripts/dev-proxy.mjs", - "language": "javascript", - "sizeLines": 39, - "fileCategory": "code" - }, - { - "path": "scripts/dev.sh", - "language": "shell", - "sizeLines": 31, - "fileCategory": "script" - }, - { - "path": "scripts/import-voynich.mjs", - "language": "javascript", - "sizeLines": 104, - "fileCategory": "code" - }, - { - "path": "scripts/start.mjs", - "language": "javascript", - "sizeLines": 284, - "fileCategory": "code" - }, - { - "path": "scripts/verify-marginalia.mjs", - "language": "javascript", - "sizeLines": 132, - "fileCategory": "code" - }, - { - "path": "scripts/verify-readings-rail.mjs", - "language": "javascript", - "sizeLines": 171, - "fileCategory": "code" - }, - { - "path": "skills-lock.json", - "language": "json", - "sizeLines": 17, - "fileCategory": "config" - }, - { - "path": "start.cmd", - "language": "batch", - "sizeLines": 18, - "fileCategory": "script" - }, - { - "path": "start.command", - "language": "command", - "sizeLines": 4, - "fileCategory": "code" - }, - { - "path": "start.sh", - "language": "shell", - "sizeLines": 17, - "fileCategory": "script" - }, - { - "path": "tsconfig.base.json", - "language": "json", - "sizeLines": 19, - "fileCategory": "config" - } - ], - "totalFiles": 666, - "filteredByIgnore": 0, - "estimatedComplexity": "very-large", - "stats": { - "filesScanned": 666, - "byCategory": { - "docs": 74, - "config": 309, - "code": 263, - "infra": 1, - "markup": 15, - "script": 4 - }, - "byLanguage": { - "markdown": 69, - "json": 306, - "unknown": 4, - "yaml": 4, - "q-counter": 6, - "jsonl": 8, - "txt": 5, - "html": 7, - "css": 8, - "otf": 6, - "svelte": 40, - "typescript": 186, - "javascript": 8, - "mts": 1, - "astro": 2, - "snap": 1, - "shell": 3, - "batch": 1, - "command": 1 - } - } -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 56a00f30..bf6b3d6a 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,11 @@ pnpm-debug.log* .env.* !.env.example +# ───────────────────────────────────────────────────────────── +# Shell-redirect residue (accidental `cmd > --output`-style typos) +# ───────────────────────────────────────────────────────────── +/--output + # ───────────────────────────────────────────────────────────── # Editor / OS # ───────────────────────────────────────────────────────────── From 7c05375eece7d7fb89fcf879afb9d9236c5a5469 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:49:44 -0700 Subject: [PATCH 07/24] fix(studio): clear remaining typecheck errors (binding, collab test, publish-flows, save-queue) - binding.ts: FileSystemWritableFileStream.write's chunk type excludes SharedArrayBuffer-backed views; fflate's zip stream never produces one, so assert Uint8Array instead of the wrong-generic ArrayBufferView cast. - collab.test.ts: used AnnotationSession's private `log` where every other line in the file already used the public `entries` getter for the same value. - publish-flows.svelte.ts: LogLookup's real signature takes a plain string exhibitId; annotating the three lambdas' parameter as the branded LogicalId narrowed it below what the callback type allows (contravariance violation). - save-queue.svelte.ts: non-null assert the last-message index, already guarded by the preceding length check (existing codebase idiom for noUncheckedIndexedAccess). `pnpm --filter @archie/studio exec tsc --noEmit` is now fully green; all 148 tests still pass. --- apps/studio/src/binding.ts | 5 ++++- apps/studio/src/collab.test.ts | 2 +- apps/studio/src/publish-flows.svelte.ts | 8 ++++---- apps/studio/src/save-queue.svelte.ts | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/studio/src/binding.ts b/apps/studio/src/binding.ts index 0170b386..52900a5c 100644 --- a/apps/studio/src/binding.ts +++ b/apps/studio/src/binding.ts @@ -88,7 +88,10 @@ export async function saveZipToDisk(fs: ZipFilesystem, filename: string): Promis const writable = await handle.createWritable(); try { await fs.streamZip({ - write: (chunk) => writable.write(chunk as unknown as ArrayBufferView), + // fflate's zip stream always hands back a freshly-allocated (never SharedArrayBuffer-backed) + // Uint8Array; FileSystemWritableFileStream.write's type is narrower than Uint8Array's default + // generic (which allows ArrayBufferLike, i.e. SharedArrayBuffer too). + write: (chunk) => writable.write(chunk as Uint8Array), close: () => writable.close(), }); } catch (e) { diff --git a/apps/studio/src/collab.test.ts b/apps/studio/src/collab.test.ts index 4b7dc6ae..da6a98a2 100644 --- a/apps/studio/src/collab.test.ts +++ b/apps/studio/src/collab.test.ts @@ -16,7 +16,7 @@ describe("collabBreakdown — who wrote what, on live notes", () => { note(priya, 1); note(priya, 2); const me = new AnnotationSession(asClientId("me"), priya.entries); const mine = note(me, 3); - const b = collabBreakdown({ ex: me.log }, asClientId("me")); + const b = collabBreakdown({ ex: me.entries }, asClientId("me")); expect(b).toEqual({ others: [{ editor: "priya", count: 2 }], yours: 1 }); const afterDelete = new AnnotationSession(asClientId("me"), me.entries); diff --git a/apps/studio/src/publish-flows.svelte.ts b/apps/studio/src/publish-flows.svelte.ts index 034114f0..2edf10a3 100644 --- a/apps/studio/src/publish-flows.svelte.ts +++ b/apps/studio/src/publish-flows.svelte.ts @@ -7,7 +7,7 @@ // library-meta.svelte.ts): the $state container is never reassigned, getters stay live. import { MemoryFilesystem, publishLibrary, libraryToZipFs, collectFiles, publishToGitHub, renderMarkdown, - type Filesystem, type Library, type AnnotationLog, type BrokenLink, type GitHubTarget, type PublishProgress, type LogicalId, + type Filesystem, type Library, type AnnotationLog, type BrokenLink, type GitHubTarget, type PublishProgress, } from "@render/core"; import { supportsFileStreamSave, saveZipToDisk } from "./binding.js"; import { pickFolderBinding } from "./folder-backend.js"; @@ -143,7 +143,7 @@ export function createPublishFlows(deps: PublishDeps) { async function projectSite(withOriginals: boolean): Promise<{ fs: MemoryFilesystem; brokenLinks: BrokenLink[] }> { const logs = await deps.loadAllLogs(); const fs = new MemoryFilesystem(); - const { brokenLinks } = await publishLibrary(fs, deps.buildFullLibrary(), (id: LogicalId) => logs[id] ?? [], { baseUrl: deps.baseUrl, getAsset, getThumbnail, tileObject, tileRemote, ...STATIC_PAGE_OPTS, ...(withOriginals ? { getOriginal: (slug: string, name: string) => readOriginalBytes(slug, name) } : {}) }); + const { brokenLinks } = await publishLibrary(fs, deps.buildFullLibrary(), (id: string) => logs[id] ?? [], { baseUrl: deps.baseUrl, getAsset, getThumbnail, tileObject, tileRemote, ...STATIC_PAGE_OPTS, ...(withOriginals ? { getOriginal: (slug: string, name: string) => readOriginalBytes(slug, name) } : {}) }); if (brokenLinks.length > 0) console.warn(`Publish: ${brokenLinks.length} broken intra-Library link(s) degraded to plain text`, brokenLinks); return { fs, brokenLinks }; } @@ -156,13 +156,13 @@ export function createPublishFlows(deps: PublishDeps) { // ONE zip builder for the three zip paths (project Save / dialog download / local publish). async function buildZipFs() { const logs = await deps.loadAllLogs(); - return libraryToZipFs(deps.buildFullLibrary(), (id: LogicalId) => logs[id] ?? [], { baseUrl: deps.baseUrl, getAsset, getThumbnail, tileObject, tileRemote, ...STATIC_PAGE_OPTS }); + return libraryToZipFs(deps.buildFullLibrary(), (id: string) => logs[id] ?? [], { baseUrl: deps.baseUrl, getAsset, getThumbnail, tileObject, tileRemote, ...STATIC_PAGE_OPTS }); } // ONE folder writer for the two folder sinks (binding autosave/Save + local publish). Takes the // Filesystem seam directly (FSA or Tauri), so the caller owns capability selection (folder-backend). async function writeTree(fs: Filesystem) { const logs = await deps.loadAllLogs(); - await publishLibrary(fs, deps.buildFullLibrary(), (id: LogicalId) => logs[id] ?? [], { baseUrl: deps.baseUrl, getAsset, getThumbnail, tileObject, tileRemote, ...STATIC_PAGE_OPTS }); + await publishLibrary(fs, deps.buildFullLibrary(), (id: string) => logs[id] ?? [], { baseUrl: deps.baseUrl, getAsset, getThumbnail, tileObject, tileRemote, ...STATIC_PAGE_OPTS }); } /** Download the library as .archie.zip (size-guarded). False = the user declined/cancelled. */ async function downloadProjectZip(): Promise { diff --git a/apps/studio/src/save-queue.svelte.ts b/apps/studio/src/save-queue.svelte.ts index 47202c25..d6b9ad72 100644 --- a/apps/studio/src/save-queue.svelte.ts +++ b/apps/studio/src/save-queue.svelte.ts @@ -26,7 +26,7 @@ export const saveStatus = { }, get error(): string | null { const msgs = Object.values(s.errors); - return msgs.length > 0 ? msgs[msgs.length - 1] : null; + return msgs.length > 0 ? msgs[msgs.length - 1]! : null; }, get pending(): number { return s.pending; From df866c870efd800960acbdad51ed33eb59bb2cff Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:50:21 -0700 Subject: [PATCH 08/24] chore: remove stale anti-pattern-report.txt one-shot lint dump No generator script for this report exists anywhere in the repo, so a committed copy can only drift the moment code changes. Ledger ledgers/ARTIFACTS.md row 2. --- .gitignore | 6 + anti-pattern-report.txt | 351 ---------------------------------------- 2 files changed, 6 insertions(+), 351 deletions(-) delete mode 100644 anti-pattern-report.txt diff --git a/.gitignore b/.gitignore index bf6b3d6a..fea7cff5 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,12 @@ pnpm-debug.log* # ───────────────────────────────────────────────────────────── /--output +# ───────────────────────────────────────────────────────────── +# One-shot analysis dumps — no generator script lives in this repo; +# regenerate with whatever external tool produced it, never commit the output. +# ───────────────────────────────────────────────────────────── +/anti-pattern-report.txt + # ───────────────────────────────────────────────────────────── # Editor / OS # ───────────────────────────────────────────────────────────── diff --git a/anti-pattern-report.txt b/anti-pattern-report.txt deleted file mode 100644 index b638d47a..00000000 --- a/anti-pattern-report.txt +++ /dev/null @@ -1,351 +0,0 @@ -=== FINDINGS === -[catch-all] .agents/skills/teach/.scout/shoot.mjs:17 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] apps/studio/src/binding.ts:95 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] apps/studio/src/save-queue.svelte.ts:47 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] apps/studio/src/store.ts:298 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] docs/learn/assets/models.js:115 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] docs/learn/assets/models.js:121 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:113 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:127 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:178 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:201 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:246 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:278 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:304 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:342 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:386 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:399 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:400 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:420 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:515 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/capture-screenshots.mjs:70 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/verify-marginalia.mjs:27 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/verify-readings-rail.mjs:148 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/verify-readings-rail.mjs:154 -- bare catch-all with no rethrow/reject/error-return/logging in body -[catch-all] scripts/verify-readings-rail.mjs:28 -- bare catch-all with no rethrow/reject/error-return/logging in body -[console-only-error] packages/archie-viewer/src/element.ts:257 -- console.error with no UI feedback in surrounding context -[fire-and-forget] .agents/skills/teach/.scout/diag.mjs:2 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] .agents/skills/teach/.scout/diag.mjs:3 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] .agents/skills/teach/.scout/shoot.mjs:12 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] .agents/skills/teach/.scout/shoot.mjs:13 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/AvEditor.svelte:230 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/AvEditor.svelte:316 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/bake.ts:35 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/binding-store.svelte.ts:52 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/binding.ts:74 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/dzi-slicer.ts:89 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:105 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:107 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:120 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:122 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:129 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:137 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/exhibit-session.svelte.ts:61 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:40 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:42 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:44 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:47 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:55 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:57 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:58 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/folder-backend.ts:64 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/handles-db.ts:24 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:100 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:104 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:118 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:119 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:127 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:151 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:152 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:161 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:171 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:177 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:183 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:189 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:190 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:436 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/ingest-flows.ts:99 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/library-meta.svelte.ts:30 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/library-meta.svelte.ts:54 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/library-meta.svelte.ts:55 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/library-meta.svelte.ts:56 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/library-meta.svelte.ts:60 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/library-meta.svelte.ts:61 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:144 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:146 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:153 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:154 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:158 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:164 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:165 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:169 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:170 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:171 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:191 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/publish-flows.svelte.ts:192 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:177 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:178 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:179 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:180 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:185 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:191 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:198 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:218 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:28 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:29 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:40 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:43 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:44 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/store.ts:97 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:67 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:68 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:70 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:76 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:77 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:82 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/studio/src/tauri-fs.ts:83 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/viewer/src/components/ViewerShell.svelte:276 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/viewer/src/published.ts:26 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/viewer/src/published.ts:306 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] apps/viewer/src/published.ts:315 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/archie-viewer/src/reader.ts:5 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/archie-viewer/src/reader.ts:65 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:43 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:50 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:51 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:52 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:53 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:54 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:55 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:56 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:60 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:61 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:64 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:65 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:67 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:73 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:74 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:75 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:76 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:77 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:78 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:79 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:80 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:84 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:85 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:86 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:90 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:91 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:92 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/conformance.ts:93 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/fsa.ts:12 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/fsa.ts:15 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/fsa.ts:29 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/fsa.ts:32 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/memory.ts:22 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:102 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:106 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:112 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:116 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:130 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:63 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:73 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:79 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:93 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/tauri.ts:94 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/zip.ts:161 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/zip.ts:168 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/zip.ts:172 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/zip.ts:173 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/fs/zip.ts:67 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:164 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:166 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:173 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:174 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:175 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:177 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:179 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:184 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:191 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/ghpages.ts:201 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/marker.ts:53 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/portable.ts:141 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/portable.ts:88 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:37 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:38 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:39 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:40 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:87 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:90 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/read.ts:91 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:143 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:144 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:145 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:146 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:150 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:151 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:152 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:153 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:166 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:169 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:170 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:171 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:172 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:196 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:199 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:200 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:202 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:221 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:228 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:232 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:233 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:237 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:239 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:240 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:241 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:242 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:248 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:251 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:259 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:261 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:262 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:263 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:264 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:279 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:282 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:285 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:321 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:323 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:325 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:326 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:327 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:328 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:340 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:341 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:342 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:347 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:354 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:355 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:357 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:368 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:369 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:376 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:378 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/publish/site.ts:380 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/session/session.ts:235 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/session/session.ts:243 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/session/session.ts:79 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:18 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:19 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:20 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:21 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:25 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:26 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:35 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:38 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:39 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-core/src/spine/persist.ts:51 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-mount/src/mount.ts:111 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] packages/render-mount/src/read-mount.ts:206 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:158 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:159 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:160 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:162 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:164 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:165 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:166 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:172 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:173 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:175 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:176 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:340 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:373 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:374 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:58 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/capture-screenshots.mjs:59 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:101 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:102 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:103 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:104 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:107 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:109 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:111 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:112 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:115 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:116 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:117 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:119 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:121 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:124 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:64 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:66 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:68 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:69 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:70 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:71 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:72 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:74 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:79 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:80 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:81 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:82 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:86 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:87 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:88 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:89 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:90 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:93 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:94 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-marginalia.mjs:96 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:100 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:102 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:103 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:104 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:106 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:108 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:113 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:114 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:115 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:116 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:117 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:118 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:119 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:120 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:121 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:125 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:126 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:127 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:128 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:129 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:130 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:131 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:137 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:139 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:140 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:141 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:146 -- await with no try/catch or .catch() in nearby context -[fire-and-forget] scripts/verify-readings-rail.mjs:147 -- await with no try/catch or .catch() in nearby context -[impact-scope] apps/studio/src/seed-data.ts:0 -- 3/5 importers of seed-data have no tests (Tier 0: 5 direct callers, Tier 1: depth 2 transitive=79) -[impact-scope] apps/viewer/fixtures/sample-data.ts:0 -- 4/9 importers of sample-data have no tests (Tier 0: 9 direct callers, Tier 1: depth 2 transitive=159) -[impact-scope] packages/archie-viewer/src/element.ts:0 -- 14/38 importers of element have no tests (Tier 0: 38 direct callers, Tier 1: depth 2 transitive=306) -[impact-scope] packages/render-core/src/publish/marker.ts:0 -- 15/45 importers of marker have no tests (Tier 0: 45 direct callers, Tier 1: depth 2 transitive=339) -[impact-scope] packages/render-mount/src/read-mount.test.ts:0 -- 1/2 importers of read-mount.test have no tests (Tier 0: 2 direct callers, Tier 1: depth 2 transitive=6) -[impact-scope] packages/render-mount/src/read-mount.ts:0 -- 2/7 importers of read-mount have no tests (Tier 0: 7 direct callers, Tier 1: depth 2 transitive=130) -[silent-catch] apps/studio/src/ingest-flows.ts:201 -- catch body logs error but never surfaces to user -[silent-catch] packages/archie-viewer/src/element.ts:254 -- catch body logs error but never surfaces to user -[unpaired-resource] apps/studio/src/App.svelte:48001 -- 1 acquire calls but no release in file (lock/unlock) -[untested-churn] apps/studio/src/App.svelte:0 -- 44 commits (6mo), no test file -[untested-churn] apps/studio/src/ExhibitOverview.svelte:0 -- 12 commits (6mo), no test file -[untested-churn] apps/studio/src/LibraryHome.svelte:0 -- 11 commits (6mo), no test file -[untested-churn] apps/studio/src/NarrativeEditor.svelte:0 -- 9 commits (6mo), no test file -[untested-churn] apps/studio/src/PublishDialog.svelte:0 -- 10 commits (6mo), no test file -[untested-churn] apps/studio/src/store.ts:0 -- 10 commits (6mo), no test file -[untested-churn] apps/viewer/src/components/ExhibitView.svelte:0 -- 18 commits (6mo), no test file -[untested-churn] apps/viewer/src/components/MediaPlayer.svelte:0 -- 12 commits (6mo), no test file -[untested-churn] apps/viewer/src/components/NarrativeReader.svelte:0 -- 18 commits (6mo), no test file -[untested-churn] apps/viewer/src/components/Reader.svelte:0 -- 18 commits (6mo), no test file -[untested-churn] apps/viewer/src/components/ReadingLegend.svelte:0 -- 9 commits (6mo), no test file -[untested-churn] apps/viewer/src/components/ViewerShell.svelte:0 -- 13 commits (6mo), no test file -[untested-churn] packages/render-svelte/src/Canvas.svelte:0 -- 12 commits (6mo), no test file - -=== RISK SCORES === From c96b78799dbf7b6ef4aeebfa303df014313d24ff Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:51:00 -0700 Subject: [PATCH 09/24] fix(studio): replace literal NUL byte in App.svelte with \0 escape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit addPendingNotes's dedup key (`${p.objectId}\0${p.comment}`) needs a separator guaranteed absent from real data. It was written as a raw 0x00 byte pasted into the source text instead of the JS escape sequence — identical at runtime, but it made grep, ripgrep, git grep, and the fff tools treat the whole 2147-line file as binary and silently report zero matches on every search. Ledger ledgers/ARTIFACTS.md row: NUL byte. Verified: file(1) now reports text, git grep matches inside the file, studio suite green (148/148). --- apps/studio/src/App.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/studio/src/App.svelte b/apps/studio/src/App.svelte index 19868de7..0261f5c0 100644 --- a/apps/studio/src/App.svelte +++ b/apps/studio/src/App.svelte @@ -651,7 +651,7 @@ } // IngestContext hook: stage coordinate-free CSV rows, deduped by (object, comment). Returns the NEW count. function addPendingNotes(incoming: CsvPendingNote[]): number { - const key = (p: { objectId: string; comment: string }) => `${p.objectId}${p.comment}`; + const key = (p: { objectId: string; comment: string }) => `${p.objectId}\0${p.comment}`; const seen = new Set(pendingNotes.map(key)); let added = 0; for (const n of incoming) { From fb42311b649ad21fe6d64f4a43899805047859ee Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:51:13 -0700 Subject: [PATCH 10/24] fix(studio): wire the typecheck script into package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tsconfig.json + all the error fixes landed in prior commits, but the actual "typecheck": "tsc --noEmit" script was never added to package.json — pnpm -r typecheck silently skipped studio the whole time (it only runs the script in packages that declare it). Root `pnpm typecheck` now covers all 6 packages. --- apps/studio/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/studio/package.json b/apps/studio/package.json index c03626f4..2de54140 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -10,7 +10,8 @@ "dev": "node scripts/sync-learn.mjs && vite", "build": "node scripts/sync-learn.mjs && vite build", "preview": "vite preview", - "test": "vitest run" + "test": "vitest run", + "typecheck": "tsc --noEmit" }, "dependencies": { "@annotorious/openseadragon": "^3.8.2", From 9242d3fe48d8c396215f9d17ca44ee2541f7f51c Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:52:40 -0700 Subject: [PATCH 11/24] chore: add sync-dist script and record the root dist/ sync rule Root dist/ hand-mirrors packages/archie-viewer/dist/ so jsDelivr's /gh/ root-relative serving resolves the @v1 embed URL (a656cda). No build step enforced the two trees stay identical. Adds `pnpm sync-dist` (resync) and `pnpm sync-dist:check` (verify, exit 1 on drift), and documents the release rule in ADR-0019 + the README embed recipe. Ledger ledgers/ARTIFACTS.md row: dist/. --- README.md | 5 ++ ...0019-embeddable-read-only-archie-viewer.md | 7 +++ package.json | 4 +- scripts/sync-dist.mjs | 52 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 scripts/sync-dist.mjs diff --git a/README.md b/README.md index 43f2bab7..c8b2fb6a 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,11 @@ Load the runtime from jsDelivr serving the pinned `@v1` git tag, then place one ``` +> [!TIP] +> Maintainer note: that URL resolves at the **repo root** `dist/`, a hand-synced copy of +> `packages/archie-viewer/dist/` (ADR-0019 amendment). Before tagging a new `@vN`, run +> `pnpm --filter archie-viewer build && pnpm sync-dist && pnpm sync-dist:check`. + Pin `@v1` so an upstream change can't silently alter your embed. The public surface is three attributes (frozen — [ADR-0021](docs/adr/0021-archie-viewer-target-contract.md)): | Attribute | What it does | diff --git a/docs/adr/0019-embeddable-read-only-archie-viewer.md b/docs/adr/0019-embeddable-read-only-archie-viewer.md index 0cfb5d95..221ddb2b 100644 --- a/docs/adr/0019-embeddable-read-only-archie-viewer.md +++ b/docs/adr/0019-embeddable-read-only-archie-viewer.md @@ -55,6 +55,13 @@ already-pure `render-core` selectors (`geometry/selector.ts`), reusing the in-re read-only path WITHOUT regressing the editor mount (shared by both apps via `@render/svelte`). - The element name + attribute schema become a frozen public API (annomea shipped this inconsistently — `` vs ``, its `EMBED-AUDIT.md`); locked in a follow-on grill before code. +- **Amendment (2026-07-05, tend Issue 3):** jsDelivr's `/gh/` serving resolves paths at the **repo + root**, not inside a package subpath, so `packages/archie-viewer/dist/` — the actual build output — + is hand-mirrored to a root-level `dist/` (`a656cda`). This is a second copy that can silently diverge + from the package build; there is no repo-root build step to replace it with. Rule: after + `pnpm --filter archie-viewer build` and before tagging a new `@vN`, run `pnpm sync-dist` + (`scripts/sync-dist.mjs`) to resync the root copy, and `pnpm sync-dist:check` to verify it before + release — it diffs both trees and exits 1 on drift. ## Alternatives rejected diff --git a/package.json b/package.json index f9400693..c56025a6 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "build": "pnpm -r build", "build:gh-pages": "bash scripts/build-gh-pages.sh", "bundle:baseline": "node scripts/bundle-size.mjs", - "bundle:check": "node scripts/bundle-size.mjs --check" + "bundle:check": "node scripts/bundle-size.mjs --check", + "sync-dist": "node scripts/sync-dist.mjs", + "sync-dist:check": "node scripts/sync-dist.mjs --check" }, "devDependencies": { "@tauri-apps/cli": "^2.11.3", diff --git a/scripts/sync-dist.mjs b/scripts/sync-dist.mjs new file mode 100644 index 00000000..9dace3e7 --- /dev/null +++ b/scripts/sync-dist.mjs @@ -0,0 +1,52 @@ +// Sync packages/archie-viewer/dist/ to the repo root dist/. +// Canonical build output is packages/archie-viewer/dist/ (built by +// `pnpm --filter archie-viewer build`); this copy exists ONLY so the README's +// jsDelivr recipe (cdn.jsdelivr.net/gh/.../@v1/dist/archie-viewer.js) resolves +// at the repo root, which is where jsDelivr's /gh/ raw-file serving looks. +// Run before tagging a new @vN release (see docs/adr/0019, README "Embed an exhibit"). +// `--check` compares without writing and exits 1 on any drift — no baseline file, +// the source of truth is the package's own dist/. +import { cpSync, existsSync, readdirSync, readFileSync, rmSync, mkdirSync } from "node:fs"; +import { join } from "node:path"; + +const root = process.cwd(); +const src = join(root, "packages", "archie-viewer", "dist"); +const dest = join(root, "dist"); + +if (!existsSync(src)) { + console.error(`[sync-dist] source missing: ${src} — run \`pnpm --filter archie-viewer build\` first`); + process.exit(1); +} + +function listFiles(dir) { + return readdirSync(dir).sort(); +} + +if (process.argv.includes("--check")) { + if (!existsSync(dest)) { + console.error(`[sync-dist] ${dest} is missing — run \`node scripts/sync-dist.mjs\` first`); + process.exit(1); + } + const srcFiles = listFiles(src); + const destFiles = listFiles(dest); + let drifted = srcFiles.length !== destFiles.length; + if (!drifted) { + for (const name of srcFiles) { + if (!readFileSync(join(src, name)).equals(readFileSync(join(dest, name)))) { + drifted = true; + break; + } + } + } + if (drifted) { + console.error(`[sync-dist] ${dest} has drifted from ${src} — run \`node scripts/sync-dist.mjs\` to resync`); + process.exit(1); + } + console.log("[sync-dist] root dist/ matches packages/archie-viewer/dist/"); + process.exit(0); +} + +rmSync(dest, { recursive: true, force: true }); +mkdirSync(dest, { recursive: true }); +cpSync(src, dest, { recursive: true }); +console.log(`[sync-dist] copied ${src} -> ${dest}`); From 917b27489517a31cd5f9f9112200b41236d5d140 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:53:07 -0700 Subject: [PATCH 12/24] docs: close out Issue 3 ledger and status Ledger ledgers/ARTIFACTS.md: all four rows done, zero accident rows remain. ISSUES.md Issue 3 -> done 2026-07-05. --- ISSUES.md | 668 +++++++++++++++++++++++++++++++++++++++++++ ledgers/ARTIFACTS.md | 25 ++ 2 files changed, 693 insertions(+) create mode 100644 ISSUES.md create mode 100644 ledgers/ARTIFACTS.md diff --git a/ISSUES.md b/ISSUES.md new file mode 100644 index 00000000..a6240686 --- /dev/null +++ b/ISSUES.md @@ -0,0 +1,668 @@ +# ISSUES — Archie tend backlog + +Generated 2026-07-05 by a tend diagnosis. Commit examined: `2091557` (main). +Evidence gathered by two codebase walks (core packages + apps/ops surface); every +symptom below was verified against files on disk, not inferred. Issues are ordered +by leverage; directions by strength. Each **Run it** block is self-contained — +paste it into a fresh session with no skill loaded. + +--- + +## Issue 1 — CI is deploy-only and typecheck is red on main + +**Status:** queued + +**Symptom.** `.github/workflows/deploy.yml` is the only workflow; it builds +(`scripts/build-gh-pages.sh`) and deploys Pages — no vitest, no tsc, no +`astro check`. Meanwhile `pnpm typecheck` from root **fails (exit 2)**: +`packages/render-core/src/link/link-object.test.ts:30-31` (TS2339: `objectId`/`noteId` +missing on `ViewerRoute`), `packages/render-core/src/spine/wholeobject.test.ts:48` +(TS2352), and `packages/render-mount/src/mount.ts:251` (TS2345 — HANDOFF said :238, +"pre-existing"), which cascades so `render-mount`, `render-svelte`, and +`archie-viewer` all fail typecheck too. `apps/studio/package.json` has no +`typecheck` script at all. The ~1163-test suite runs only on developer machines. + +**Rungs.** L2↔L4: the README promises "both must pass" for PRs while nothing +automated has ever enforced it, and the check is currently failing. + +**Why it's high-leverage.** Every other issue's fix wants a green gate to land +behind; today a red typecheck deploys without complaint. *Lesson: continuous +integration — a check that doesn't run automatically will stop running, and a +gate never seen to fail is decoration, not protection.* + +**Loop.** Tripwire installation. Ledger `ledgers/GATE.md`. Phase 1 inventory +checks (test, typecheck per package, astro check, build); phase 2 repair each to +green locally (the 4 typecheck failures above, plus adding a studio typecheck +script); phase 3 wire into GitHub Actions on push; phase 4 trip each wire once +with a planted defect on a branch. Done: every check green in CI on main and +each witnessed red once. + +**Run it:** + +``` +Set up CI for this repo (GitHub Actions; a deploy workflow already exists at +.github/workflows/deploy.yml — add checks, don't disturb deploy). Ledger +ledgers/GATE.md: check | command | local result | CI wired | tripped red | commit. +Inventory every check the repo can run: pnpm typecheck (per package — note +apps/studio has no typecheck script; add a minimal one), per-app pnpm exec vitest +(root vitest binary fails rune tests — run per package/app), astro check for +apps/viewer, and the gh-pages build. Known-red right now: render-core +link-object.test.ts:30-31 (ViewerRoute objectId/noteId), spine/wholeobject.test.ts:48 +(TS2352), render-mount mount.ts:251 (TS2345, cascades to render-svelte and +archie-viewer). Make each check pass locally first — one fix per commit — then +wire them into a CI job on every push (Node 22+, pnpm 9, LFS checkout), then +prove each wire trips: one deliberate defect per check on a branch, watch it go +red, revert. Done only when every check is green on main AND each has been seen +to fail once. +``` + +**Strength:** Strong. + +--- + +## Issue 2 — The operational docs actively misdirect + +**Status:** queued + +**Symptom.** Three documents contradict the code they describe: +- `HANDOFF.md` (2026-06-21) says the embed feature is UNCOMMITTED on + `feat/archie-viewer-embed`, `packages/archie-viewer/` untracked, ADRs 0019-0021 + untracked, "commit required" — all of it shipped to main (`c471b93`, v1.1; + 26 tracked files in `packages/archie-viewer/`; ADRs 0019-0022 tracked). +- `docs/IMPLEMENTATION-STRATEGY.md` §"Deferred-work registry" (dated 2026-05-25) + lists as pending: IIIF Content-State wiring (shipped — ADR-0022, `content-state.ts`), + viewer empty/error states (shipped — `EmptyHall.svelte` mounted in `ViewerShell`), + search "out of v1" (shipped — `SearchOverlay.svelte` mounted in `ExhibitView`), + narrative section-authoring "next phase" (shipped — `NarrativeEditor.svelte` + lazy-mounted at `App.svelte:88-89`). README calls this file "the canonical + remaining-work list." +- `README.md:226` advertises "conflict-card resolution" as a shipped Collaboration + feature; `MergeReview.svelte` is imported by nothing (see Direction 1). + +**Rungs.** L1↔L2: the purpose-level documents describe a different product than +the code implements — in both directions. + +**Why it's high-leverage.** These are exactly the files a fresh session (or +contributor) reads first; following HANDOFF today risks re-doing or reverting +shipped work. *Lesson: documentation drift — a README that lies is worse than +none; every reader, including the AI next session, builds on the lie.* + +**Loop.** Claim-vs-reality diff over `HANDOFF.md`, `README.md`, +`docs/IMPLEMENTATION-STRATEGY.md`. Ledger `ledgers/CLAIMS.md`. Done: re-running +the full diff finds nothing. + +**Run it:** + +``` +Extract every claim HANDOFF.md, README.md ("Features", "Status & roadmap", +"Known limitations"), and docs/IMPLEMENTATION-STRATEGY.md (the deferred-work +registry) make about what this app does or what work remains, and check each +against the code; also list what the code does that these docs never mention. +Known drift to seed the diff: HANDOFF claims the archie-viewer embed is +uncommitted (it shipped in c471b93); the deferred registry lists Content-State +wiring, viewer empty states, search, and narrative section-authoring as pending +(all shipped); README:226 claims conflict-card resolution ships (MergeReview.svelte +is mounted nowhere — log this row as blocked-on-verdict, see ISSUES.md Direction 1, +don't resolve it unilaterally). Ledger ledgers/CLAIMS.md: claim | where claimed | +what the code does | type (claimed-not-implemented / implemented-not-documented / +implemented-differently) | resolution | commit | recheck. Finish the whole diff +before resolving anything; then per row fix the code, fix the docs, or deprecate +(HANDOFF.md is superseded — archiving/rewriting it is a valid resolution) — one +commit each, rechecking the row after its fix. Done when re-running the full +diff finds nothing. +``` + +**Strength:** Strong. + +--- + +## Issue 3 — Tracked artifacts that lie: a NUL byte, a `--output` file, twin bundles, stale reports + +**Status:** done 2026-07-05 — ledger: ledgers/ARTIFACTS.md + +**Symptom.** +- `apps/studio/src/App.svelte` (2147 lines, the studio's central component) + contains exactly **one NUL byte** — present in the committed blob. grep, + git grep, ripgrep, and the fff tools all treat the file as binary and silently + return zero matches; every "grep is unreliable in this repo" experience traces + to this byte. Verified: `tr -d -c '\000' < apps/studio/src/App.svelte | wc -c` → 1. +- A file literally named `--output` (113 KB, shell-redirect residue) is tracked + at repo root (committed in `5d5bf50`). +- `dist/` at root duplicates `packages/archie-viewer/dist/` (same bundle files, + hand-synced for the jsDelivr `@v1/dist` URL per `a656cda`) — two copies that + can silently diverge. +- `anti-pattern-report.txt` (40 KB, 2026-06-22) is a committed one-shot lint dump + that drifts the moment code changes; `node-compile-cache/` and + `v8-compile-cache-1000/` sit at repo root. + +**Rungs.** L3↔L4: repository structure that misleads both tools and readers about +what is source. + +**Why it's high-leverage.** The NUL byte alone silently defeats every grep-based +tool — reviews, audits, and agents have been reporting false "0 matches" on the +most important studio file. *Lesson: dead-code elimination extends to artifacts — +tracked junk isn't free; it's text your tools reread, misparse, or silently skip.* + +**Loop.** Deletion sweep adapted to tracked artifacts. Ledger +`ledgers/ARTIFACTS.md`. Done: zero accidental rows remain; every deliberate +artifact (root `dist/`) carries its reason and a sync-check. + +**Run it:** + +``` +Audit every tracked file/directory at the Archie repo root that is not source or +docs: --output (shell-redirect residue, tracked), anti-pattern-report.txt +(committed one-shot lint dump), dist/ (hand-synced twin of +packages/archie-viewer/dist/ for the jsDelivr @v1/dist URL — deliberate, verify +the two copies are byte-identical), node-compile-cache/, v8-compile-cache-1000/, +gh-pages-dist/, plus the single NUL byte inside apps/studio/src/App.svelte +(verify with: tr -d -c '\000' < apps/studio/src/App.svelte | wc -c; it makes +grep/ripgrep/git-grep treat the file as binary). Ledger ledgers/ARTIFACTS.md: +artifact | tracked? | why it exists | class (accident / generated / deliberate) | +action | commit | verified. Classify everything before deleting anything; check +.gitignore covers the generated classes. For the NUL byte: locate it (grep -abo +$'\0' apps/studio/src/App.svelte), remove it with a byte-exact edit, then prove +the fix by grepping App.svelte for a known string (e.g. MergeReview should now +be findable-or-absent honestly) and run the studio tests (pnpm --filter +@archie/studio exec vitest run). One action per commit. For root dist/: keep or +replace with a build step, but record the sync rule either way. Done at zero +accident rows and every deliberate row carrying its reason. +``` + +**Strength:** Strong. + +--- + +## Issue 4 — Silent failure on the persistence path + +**Status:** queued + +**Symptom.** Bare or degrading catches sit exactly where a local-first tool can +least afford them: `apps/studio/src/binding.ts:95`, `save-queue.svelte.ts:47`, +`store.ts:298` (bare catch-alls, no rethrow/log/surface — the "did my work +save?" path); `packages/archie-viewer/src/element.ts:254-261` renders an +**empty exhibit** on any open failure with only a console.error; +`apps/studio/src/ingest-flows.ts:446` catches every zip-open failure into one +generic alert, discarding the real reason (zip-bomb cap hit? marker mismatch?). +`apps/viewer/src/published.ts` probes degrade to null on any throw. Repo-wide +the 2026-06-22 anti-pattern report counted 24 catch-alls and 301 fire-and-forget +promises; the ones above were re-verified live. + +**Rungs.** L2↔L4: the product promises "your work autosaves"; the implementation +can fail that promise without anyone finding out. + +**Why it's high-leverage.** A swallowed save error in a no-server tool is data +loss with no support channel. *Lesson: observability — a swallowed failure still +happens; you've just agreed to learn about it from your users.* + +**Loop.** Silence audit, blast-radius-ordered (save/binding first, ingest second, +viewer degrades last). Ledger `ledgers/SILENCE.md`. Done: every row surfaced or +reported, every forced failure observed landing. + +**Run it:** + +``` +Find every error-handling site in the Archie studio and the archie-viewer element +— catch/except blocks, rejection callbacks, external calls with no failure branch. +Start from these verified sites but inventory exhaustively: apps/studio/src/ +binding.ts:95, save-queue.svelte.ts:47, store.ts:298 (bare catch-alls on the +persistence path), ingest-flows.ts:446 (generic alert discards the real zip-open +reason — zip-bomb cap vs marker mismatch should read differently), +packages/archie-viewer/src/element.ts:254-261 (open failure renders an empty +exhibit, console-only), apps/viewer/src/published.ts fetchJsonOptional/ +initLiveSource (degrade-to-null probes — some are by design; record the design +intent in-row rather than assuming). Ledger ledgers/SILENCE.md: site | trigger | +disposal today | should be | fix commit | forced check. Classify each — unhandled / +swallowed / logged-and-lost / surfaced / reported — fixing nothing; then fix so +every failure reaches a message the user sees or a log a human reads, persistence +(save-queue/binding/store) first. There is a toast layer in the studio (shipped +in e45f38b) — surface through it. Then force each fixed site's failure in a dev +run — a simulated fault (injected exception, corrupt zip fixture, unreachable +URL) counts; never fire real failures at live services — and confirm it lands +where the row says. Run per-app tests (pnpm --filter exec vitest run) after +each fix. Done when every row reads surfaced or reported (or by-design, with the +design cited) and every forced failure was observed. +``` + +**Strength:** Strong. + +--- + +## Issue 5 — The untrusted-zip open path exists twice + +**Status:** queued + +**Symptom.** `packages/archie-viewer/src/load.ts` (251 lines) and +`apps/viewer/src/published.ts` (318 lines) both define near-verbatim: +`openError()`, `openZipBytes()`, `openLibraryFromFile()`, +`SRC_MAX_BYTES = 256*1024*1024`, `openLibraryFromSrc()` (same cap logic, same +user-facing strings), and an HTTP-JSON source with the identical degrade comment. +Each file's header names the other as "donor." HANDOFF logged it as "tech debt — +not blocking." The divergence (instance-scoped vs module-global) is real but +bounded. + +**Rungs.** L3↔L4: one security-relevant concern (opening untrusted zips, with its +size caps and marker validation) implemented twice — a fix to one copy can +silently skip the other. + +**Why it's high-leverage.** This is the trust boundary for hostile input; a +future hardening (cap change, marker rule) has to be remembered twice or it's a +vulnerability in one consumer. *Lesson: canonicalization — every second way to do +the same job doubles the ways the next change can go wrong; for security seams +it doubles the attack surface too.* + +**Loop.** Canonicalization: pick the winner (likely a shared module in +`@render/core` or a new small package both consumers import, instance-scoped as +load.ts already is), enumerate every losing call site first, migrate under +tests, lock the rule. Ledger `ledgers/CANON.md`. Done: zero losing call sites +and the lock recorded. + +**Run it:** + +``` +This codebase opens untrusted .archie.zip / published-tree sources two ways: +packages/archie-viewer/src/load.ts (instance-scoped) and apps/viewer/src/ +published.ts (module-global) duplicate openError, openZipBytes, +openLibraryFromFile, SRC_MAX_BYTES, openLibraryFromSrc, and the HTTP-JSON source +near-verbatim (each header names the other as donor). Pick the winner with +reasons — note apps/viewer and packages/archie-viewer must not depend on each +other (README architecture contract: apps share only @render/* packages), so the +canonical copy likely lives in render-core or a shared package; the +instance-scoped shape (load.ts) is the more general of the two. Ledger +ledgers/CANON.md: losing call site | file | migrated commit | tests green. +Enumerate every losing call site BEFORE migrating any (beware: grep undercounts +until ISSUES.md Issue 3's NUL-byte fix lands); then migrate them all under tests +(pnpm --filter @archie/viewer exec vitest run and pnpm --filter archie-viewer +exec vitest run), committing as you go. Keep behavior identical — same caps, +same user-facing strings, marker validation still asserted before open. At zero +losing call sites, add the rule to CLAUDE.md: the untrusted-source open path +lives in one module; never copy it. Done at zero call sites and the lock recorded. +``` + +**Strength:** Strong. + +--- + +## Issue 6 — The IIIF projection core is untested + +**Status:** queued + +**Symptom.** In `render-core`, the files with no test sibling include +`iiif/presentation.ts` (148 lines — the Presentation-3 Manifest/Collection +projection, the product's interop claim), `iiif/exhibits.ts` (89), +`iiif/collection.ts` (29), `query/body.ts` (10). render-core has 67 test files +overall — coverage is strong elsewhere (spine, fs, publish) which makes this +hole specific, not systemic. + +**Rungs.** L2↔L4: "third-party IIIF tools can read your work directly" is a +headline behavior resting on the largest untested core file. + +**Why it's high-leverage.** IIIF output is consumed by external viewers (Mirador, +UV) that fail silently on malformed manifests; regressions here are invisible to +Archie's own UI. *Lesson: test coverage — tests are executable memory; they let +you change code you no longer remember without re-understanding it first.* + +**Loop.** Story-driven coverage climb scoped to `packages/render-core/src/iiif/`. +Ledger `ledgers/COVERAGE.md`. Done: every iiif/ file has behavior-asserting +tests and every exposed bug's row reads pass. + +**Run it:** + +``` +In packages/render-core, the iiif/ projection files lack test siblings: +iiif/presentation.ts (148 lines — IIIF Presentation 3 Manifest/Collection +projection), iiif/exhibits.ts (89), iiif/collection.ts (29), query/body.ts (10). +Rank by how much the app depends on them (presentation.ts first — the published +manifests at apps/viewer/public/published/*/manifest.json are its output and +serve as reference fixtures for what correct output looks like). Ledger +ledgers/COVERAGE.md: file | behavior under test | before | after | bug exposed | +fix commit | retest. Write tests that assert what the code should do — valid P3 +structure (type, items, annotation pages, Ranges for sections, requiredStatement/ +rights passthrough, the archie:geo anchor) — never tests that merely touch lines; +follow the existing test idiom (*.test.ts alongside source, run via pnpm +--filter @render/core exec vitest run). When a test exposes a real bug, give it +its own row and its own fix commit. Done when every iiif/ file has a +behavior-asserting test sibling and every bug row reads pass. +``` + +**Strength:** Worth exploring. + +--- + +## Issue 7 — The ingest boundary's negative space + +**Status:** queued + +**Symptom.** The zip path is capped (`ZIP_LIMITS` 512 MB / 50k entries / 100× +ratio, `fs/zip.ts:29`) and `?src=` is capped (`SRC_MAX_BYTES`), but the remote +IIIF manifest fetch (`fetchManifest`, caller of `apps/studio/src/iiif-import.ts`) +has **no byte cap** — the one remote-input vector without a guard. The other +ingest flows (folder import, CSV import at `App.svelte:1585`, WADM import at +`:1591`) have alert-on-error but their invalid/empty/huge cases are unprobed. + +**Rungs.** L2↔L4: user-facing import promises vs unguarded inputs at the trust +boundary. + +**Why it's high-leverage.** Ingest is where hostile or merely broken input meets +the app; each unhandled case is a hang, a flood, or a silent wrong result. +*Lesson: negative testing — the happy path is the demo, the failure paths are +the product.* + +**Loop.** Negative-space matrix over the studio's ingest flows. Ledger +`ledgers/NEGSPACE.md`. Done: every row passes — a clear error message passes, a +stack trace or hang doesn't. + +**Run it:** + +``` +For every ingest flow in the Archie studio — IIIF manifest URL import +(apps/studio/src/iiif-import.ts + its fetchManifest caller), image-folder +import, .archie.zip open (ingest-flows.ts), CSV notes import (csv-import.ts), +WADM import, VTT/SRT transcript import — probe the cases it does NOT handle: +invalid input (malformed JSON/CSV, wrong file type), empty data, huge input +(note: fetchManifest has NO byte cap today, unlike the zip path's ZIP_LIMITS — +probe with a simulated oversized response, never a real one), remote service +down/404/non-JSON 200, double-submit, mid-flow interruption. Probe a local dev +run (node scripts/start.mjs both) with test fixtures — never the live deployment; +simulate dependency failures rather than causing them. Ledger +ledgers/NEGSPACE.md: item | case | actual | verdict | fix commit | retest. Fill +every actual before fixing anything — a clear error message passes; a stack +trace, hang, or silent wrong result fails. Then fix row by row, one commit each, +running the studio tests per fix. Done when every row reads pass. +``` + +**Strength:** Worth exploring. + +--- + +## Issue 8 — Fresh-clone setup silently loses LFS + +**Status:** queued + +**Symptom.** `core.hooksPath` is set to `qa/hooks` locally. The four untracked +files there (`post-checkout`, `post-commit`, `post-merge`, `pre-push`) are the +stock Git-LFS hooks that `git lfs install` dropped into the active hooksPath — +untracked, so they vanish on a fresh clone even after `qa/hooks/install.sh` +runs, while `deploy.yml` and the `libraries/*.archie.zip` assets depend on LFS +(a broken deploy from exactly this — missing LFS in checkout — was fixed in +`a0b6dc0`). Separately, the `qa/` gate (`gate.mjs`, `features.jsonl`) is wired +to nothing in CI. + +**Rungs.** L2↔L4: the repo runs on this machine because of state the repo +doesn't contain. + +**Why it's high-leverage.** The next clone (or contributor) gets a repo whose +pushes silently skip LFS objects — the class of failure that already broke a +deploy once. *Lesson: reproducible environments — if the app only runs on your +machine, you own a machine, not software; every setup step lives in the repo, +as automation before prose.* + +**Loop.** Cold-start rehearsal scoped to clone→hooks→LFS→dev-servers. Ledger +`ledgers/COLDSTART.md`. Done: a fresh clone in a clean directory reaches working +dev servers and LFS-correct pushes with zero undocumented steps. + +**Run it:** + +``` +In a clean directory, get Archie running from a fresh git clone — never a copy +of the working folder. Ledger ledgers/COLDSTART.md: prerequisite | where +consumed | documented? | stumble | fix commit | clean rerun. First inventory +every prerequisite the repo consumes: Node 22+ (README), pnpm 9+, git-lfs +(libraries/*.archie.zip are LFS-tracked; deploy.yml checks out with lfs:true), +core.hooksPath=qa/hooks (set by qa/hooks/install.sh — but the stock LFS hooks +post-checkout/post-commit/post-merge/pre-push in qa/hooks are UNTRACKED in the +original repo, so a fresh clone loses LFS hook wiring even after install.sh; +this is the known bug to fix — either track LFS-invoking hooks in qa/hooks or +have install.sh run git lfs install --hookspath-aware), and any seed/gen steps +(vite-node apps/viewer/scripts/gen-published.mts). Then rehearse: clone, follow +only committed files + README, reach node scripts/start.mjs both serving studio +and viewer, and verify git lfs status is functional — logging every stumble +verbatim and fixing nothing. Then fix per row — automation over prose — commit +per row (in the real repo, not the rehearsal clone), and re-rehearse from +scratch until a full run needs zero undocumented steps. +``` + +**Strength:** Worth exploring. + +--- + +## Issue 9 — The showroom exhibit is stranded at ~80% + +**Status:** queued + +**Symptom.** `docs/showroom/` holds the full prep — `exhibit.md` (4 readings, +21-section tour), 21 coordinate-free CSVs (87 rows, verified by `verify.mjs`), +`ASSEMBLE.md`, `SHOWROOM-NOTES.md` — and 21/21 screenshots exist in +`docs/screenshots/auto/`. But the ASSEMBLE step never ran: no `showroom/` in +`apps/viewer/public/published/`, no showroom fixture, and +`docs/plans/SHOWROOM-EXHIBIT-PLAN.md:104-110` still ends on "Open decisions +(gating)" that HANDOFF claims were decided. + +**Rungs.** L1↔L2: a documented deliverable ("Archie annotates Archie" — feature +list, tutorial, and showroom in one) exists as prep but not as product. + +**Why it's high-leverage.** It's the highest-value marketing/onboarding artifact +the project has designed, and it dogfoods CSV import + region placement — the +assembly is itself a product test. *Lesson: end-to-end journeys — the assembly +was deliberately designed as a human-in-Studio session (coordinate-free CSVs so +the curator draws boxes); an 80%-done deliverable with no tracking row quietly +becomes 0%.* + +**Loop.** Journey walk riding `docs/showroom/ASSEMBLE.md`, with you as the hands +for the draw-boxes steps. Ledger `ledgers/SHOWROOM.md`. Done: the showroom +exhibit is published in the viewer tree (or the deliverable is explicitly parked +with its reason in the plan doc). + +**Run it:** + +``` +Assemble the Archie showroom exhibit per docs/showroom/ASSEMBLE.md: build the +exhibit from the 21 PNGs in docs/screenshots/auto/ (21 objects), create the 4 +readings (studio/viewer/embed/power — colours in docs/showroom/exhibit.md), +import the 21 CSVs from docs/showroom/csv/ via the Studio CSV import (each row +becomes a pending note; verify counts against node --experimental-strip-types +docs/showroom/verify.mjs → 87 rows), then the region-drawing pass ("Set area") +— this step needs a human curator: run the studio locally (node scripts/start.mjs +both), drive everything scriptable, and recruit me as the hands for drawing, +telling me exactly which object/note/region is next and logging what I report. +Wire the 21-section narrative tour, set metadata, publish into the viewer tree. +Ledger ledgers/SHOWROOM.md: step | expected | actual | friction 0-3 | fix commit +| re-walk. Every stumble in the CSV-import/pending-notes/Set-area flow is +product feedback — log it with a friction score; out-of-scope bugs go to +ISSUES.md as queued candidates, not fixed mid-walk. First, resolve the plan's +open decision: does the showroom live as a permanent seed fixture or a +hand-built published exhibit — ask me before building. Done when the showroom +exhibit is published and the walk log is complete, or the deliverable is +explicitly parked with its reason recorded in docs/plans/SHOWROOM-EXHIBIT-PLAN.md. +``` + +**Strength:** Worth exploring (needs the user in the loop by design). + +--- + +## Directions + +### Direction 1 — The collaboration machinery is built, tested, and unreachable + +**Status:** queued + +**Surplus.** `apps/studio/src/MergeReview.svelte` (conflict cards; its own header +calls it the "#1 validation-priority invention") and `IdentityPrompt.svelte` are +imported by no component — `App.svelte` (2147 lines) mounts neither. +`AnnotationSession.importChanges()` (`session.ts:147`) has no app caller. The +spine's DAG-classification layer — `lineage`, `ancestors`, `commonAncestor`, +`classifyMerge`, `classifyLogical`, `conflictTiebreak` in `spine/merge.ts` — has +zero callers outside its own file and tests. The only live "collaboration" path +(`ingest-flows.ts:454`) **replaces** the project on zip open; it never merges. +Meanwhile `README.md:226` claims "Silent DAG merge; conflict-card resolution; +identity prompt" as shipped. + +**Rungs.** L3/L4 → L2: a whole subsystem out-provides a product surface that +doesn't exist. + +**Who feels it.** The educator/collaborator personas the README courts: a +teacher receiving 30 student zips today opens each one and watches it *overwrite* +their library — the workaround is manual, one-browser-profile-per-student. +*Lesson: product discovery — a capability no user can reach doesn't exist for +them; the cheapest item on any roadmap is one the backend already does.* + +**Intent.** Forgotten-latent, most likely: the README and +`IMPLEMENTATION-STRATEGY.md:266` both claim it shipped — this reads as work that +fell out of the mount tree, not deliberate deferral. `unknown` on the deeper +DAG-classification functions. + +**Loop.** Capability-reach diff scoped to collaboration/merge. Ledger +`ledgers/CAPABILITY.md`. Done: every gated/orphaned operation verdicted with +reason — nothing built. + +**Run it:** + +``` +List every operation the Archie collaboration/merge subsystem exposes — start +from packages/render-core/src/spine/merge.ts (lineage, ancestors, commonAncestor, +classifyMerge, classifyLogical, conflictTiebreak, resolveConflict, headsOf), +session.ts (importChanges:147, resolveConflict path), and the studio components +MergeReview.svelte and IdentityPrompt.svelte — and record each one's user path +and gate. Read paths from code only — note apps/studio/src/App.svelte contains +a NUL byte that makes grep report false zero-matches; use grep -a or Read +(see ISSUES.md Issue 3). Known evidence: MergeReview/IdentityPrompt are mounted +nowhere; importChanges has no app caller; opening a colleague's zip +(ingest-flows.ts openZip → replaceProjectFrom) REPLACES rather than merges; yet +README.md:226 claims conflict-card resolution shipped. Ledger +ledgers/CAPABILITY.md: operation | defined at | user path | gate | intent | +class (reachable / gated / orphaned) | verdict | commissioned as. Inventory +everything before judging anything — a second full pass must add no rows; read +each orphaned row's intent from comments and git history (when did MergeReview +last change, was a mount ever removed?). Then bring me the orphaned rows for +verdicts in clusters (merge-UI, import-merge path, DAG-classification functions) +— pursue / park / reject, my reason logged in-row. Build nothing, open no gate: +a pursue only commissions a spec interview, pre-mortem, or prototype brief, its +prompt written into the row; a reject on the DAG functions queues a deletion +sweep, and either verdict resolves the README claim row from ledgers/CLAIMS.md +(Issue 2). Done when every orphaned row holds a verdict and its reason. +``` + +**Strength:** Strong. + +### Direction 2 — Version history is written forever and shown never + +**Status:** queued + +**Surplus.** The annotation spine persists full provenance: `mergeParents` +serialized as `archie:mergeParents` (`spine/serialize.ts:112`, read back at +`deserialize.ts:62`) with zero display consumers; `lastEditor` written on every +append (`session.ts:98/116/191`) whose only display site is the unmounted +`MergeReview.svelte:51`. The append-only version-parent DAG — the README's +"core innovation" — has no version-history view in studio or viewer. + +**Rungs.** L4 → L2: the data model's most distinctive stored value never reaches +a user's eyes. + +**Who feels it.** The DH-scholar persona: "notes are versioned" is a citability +promise, but a scholar wanting to see or cite an earlier version of a note has +no surface — the workaround is keeping dated zip exports by hand. +*Lesson: dark data — every value stored but never shown is a feature you already +paid for and forgot to ship; surfacing beats greenfield.* + +**Intent.** Designed-latent at the spine level (ADR-0003 chose append-only +deliberately, non-destructive edits are load-bearing for merge); `unknown` +whether a history *view* was ever scoped — no ADR or deferred-registry row +mentions one. + +**Loop.** Dark-data census scoped to the spine's persisted values. Ledger +`ledgers/DARKDATA.md`. Done: every dark row verdicted — nothing built. + +**Run it:** + +``` +Inventory every value the Archie annotation spine stores or computes and keeps — +walk packages/render-core/src/spine/ (log, heads, serialize: note +archie:mergeParents at serialize.ts:112) and session.ts (lastEditor written at +:98/116/191), plus what publish/site.ts projects into the published tree — and +trace which ever reach a user through a studio screen, viewer surface, published +IIIF output, or export. Evidence from code and git only; name fields, not data. +No grep hits is not yet dark — check wildcard serialization paths (the IIIF +projection may carry values into manifest.json that no viewer displays: that is +surfaced-to-IIIF-but-dark-in-app, record it as its own class note). Known +candidates: mergeParents (zero display consumers), lastEditor (only display +site is the unmounted MergeReview.svelte:51), full version-parent lineage +(append-only log per ADR-0003 — read that ADR for intent before classifying). +Ledger ledgers/DARKDATA.md: value | written at | surfaced at | class (surfaced / +internal / dark) | intent | verdict | commissioned as. Classify everything +before judging anything — a second full pass must add no rows. Then bring me +the dark rows for verdicts in clusters sharing an intent (provenance/history +values together) — pursue / park / reject, my reason logged in-row. Build and +delete nothing: a pursue only commissions a spec interview, pre-mortem, or +prototype brief (e.g. "a note's History panel" spec interview), its prompt +written into the row. Done when every dark row holds a verdict and its reason. +``` + +**Strength:** Strong. + +### Direction 3 — The embed element outgrew its snippet generator + +**Status:** queued + +**Surplus.** `packages/archie-viewer/src/element.ts:74` observes four attributes +— `src`, `target`, `iiif-content`, `offline` — all shipped, ADR-blessed +(0021/0022), and documented in `recipes/`. The one UI that hands users their +embed code, `apps/studio/src/PublishDialog.svelte:73-74`, emits only +``. Deep-linking, offline/kiosk mode, and IIIF +Content-State are reachable only by hand-editing HTML against the recipes. + +**Rungs.** L2 (element capability) → L2 (studio surface): one feature's own +halves out of step. + +**Who feels it.** The educator or curator embedding an exhibit: to deep-link a +specific note into a course page they must find `recipes/EMBED.md` and hand-write +the cite-ladder hash. The Cmd+K citation UI already computes these routes +in-app. *Lesson: product discovery — the cheapest roadmap item is one the +backend already does; here even the UI for composing the value (Cmd+K) already +exists, just not connected to the snippet.* + +**Intent.** Designed-latent for the attributes themselves (recipes document them +deliberately); `unknown` for the dialog gap — likely just sequencing +(PublishDialog's snippet shipped in the same wave the attributes were landing). + +**Loop.** Capability-reach diff, small scope. Ledger `ledgers/CAPABILITY.md` +(same ledger as Direction 1, separate cluster). Done: each unexposed attribute +verdicted. + +**Run it:** + +``` +List every capability the element exposes (packages/ +archie-viewer/src/element.ts:74 — observedAttributes src, target, iiif-content, +offline; plus behaviors each unlocks per docs/adr/0021 and 0022 and recipes/) +and record which the Studio's embed-snippet generator +(apps/studio/src/PublishDialog.svelte:73-74 — currently emits src only, plus an +iframe fallback) lets an author reach. Also record adjacent in-app sources of +the values (the Cmd+K citation flow already computes cite-ladder routes usable +as target). Ledger ledgers/CAPABILITY.md, new section "embed-snippet": operation +| defined at | user path | gate | intent | class | verdict | commissioned as. +Inventory before judging; read intent from the ADRs and recipes (documented = +deliberate capability; absent from the dialog may be sequencing, check git +history of PublishDialog.svelte). Then bring me the rows for verdicts — +pursue / park / reject with my reason in-row. Build nothing: a pursue +commissions a spec interview or prototype brief (e.g. "snippet builder with +target picker and offline toggle"), its prompt written into the row. Done when +every non-reachable capability holds a verdict and its reason. +``` + +**Strength:** Worth exploring. + +--- + +## Top recommendation + +**Issue 1 — tripwire installation.** The typecheck is red on main and nothing +automated runs the ~1163 tests: that's a burning platform, and every other fix +in this file wants a green gate to land behind. Run Issue 3 (the NUL byte) +immediately after — or fold its App.svelte fix into Issue 1's repair phase — +because until that byte is gone, every grep-based verification in the other +loops silently lies about the studio's largest file. + +**Top direction:** Direction 1 — the collaboration machinery. Strong surplus, +already claimed shipped in the README, and its verdict unblocks a row in Issue +2's claims diff. It converges to decisions, not builds — cheap to run whenever +you have verdict energy. diff --git a/ledgers/ARTIFACTS.md b/ledgers/ARTIFACTS.md new file mode 100644 index 00000000..a11733d3 --- /dev/null +++ b/ledgers/ARTIFACTS.md @@ -0,0 +1,25 @@ +# ARTIFACTS — tracked-artifact audit (ISSUES.md Issue 3) + +Inventory taken 2026-07-05 against `main` @ `8de4a8f`. Deletion sweep adapted to tracked +artifacts, plus the byte-exact NUL fix. Classify everything before touching anything. + +| artifact | tracked? | why it exists | class | action | commit | verified | +|---|---|---|---|---|---|---| +| `--output` (repo root, 113 KB) | yes, committed `5d5bf50` | shell-redirect residue — a command's stdout was accidentally redirected into a literal file named `--output` instead of a flag being consumed | accident | `git rm`; add `/--output` to `.gitignore` so the same typo can't recommit it | `d8017be` | verified: `git ls-files -- --output` empty | +| `anti-pattern-report.txt` (repo root, 40 KB, 351 lines) | yes, committed `0c3717e`, last touched `e45f38b` | one-shot dump from an external lint/anti-pattern scan tool; no generator script exists anywhere in this repo (checked `.agents/`, `qa/`, `scripts/` — none produce this format), so it can only drift the moment code changes and can never be regenerated in-repo | accident | `git rm`; add `anti-pattern-report.txt` to `.gitignore` | `df866c8` | verified: `git ls-files anti-pattern-report.txt` empty | +| `dist/` (repo root, 6 files) | yes, committed `c471b93` + sync commit `a656cda` ("publish dist/ at repo root to match the jsDelivr @v1/dist embed URL") | deliberate hand-sync twin of `packages/archie-viewer/dist/`, required because the README's jsDelivr recipe (`README.md:260`) pins `cdn.jsdelivr.net/gh/.../dist/archie-viewer.js` at the **repo root**, not the package subpath | deliberate | keep (no repo-root build step exists to replace it); confirmed byte-identical to `packages/archie-viewer/dist/` today (`diff -rq` → no output); added `scripts/sync-dist.mjs` (+ `pnpm sync-dist` / `pnpm sync-dist:check`) and documented the release rule in ADR-0019 + README so a future `archie-viewer` rebuild can't silently diverge the root copy | `9242d3f` | verified byte-identical pre-fix (`diff -rq`); `pnpm sync-dist:check` passes post-fix | +| `node-compile-cache/` (repo root, untracked) | no | Node/tsc compile cache, disk-only | generated | none — `.gitignore:27` already covers `node-compile-cache/` | n/a | verified: `git ls-files` empty, `.gitignore` line present | +| `v8-compile-cache-1000/` (repo root, untracked) | no | V8 compile cache, PID-scoped, disk-only | generated | none — `.gitignore:28` already covers `v8-compile-cache-*/` | n/a | verified: `git ls-files` empty, `.gitignore` line present | +| `gh-pages-dist/` (repo root, untracked) | no | local output of `scripts/build-gh-pages.sh`, disk-only | generated | none — `.gitignore:15` already covers `gh-pages-dist/` | n/a | verified: `git ls-files` empty, `.gitignore` line present | +| NUL byte in `apps/studio/src/App.svelte` (line 654, byte offset 48001) | yes (part of a tracked source file, not a standalone artifact) | a dedup-key builder in `addPendingNotes` — `` `${p.objectId}\x00${p.comment}` `` — needed a separator character guaranteed not to appear in real data; the author (or a paste) put a **literal raw NUL byte** in the source text instead of writing the JS/TS escape sequence `\0`. Runtime behavior is identical either way, but the raw byte makes grep, ripgrep, `git grep`, and the fff tools treat the entire 2147-line file as binary and silently report zero matches — confirmed as the root cause of every "grep is unreliable in this repo" experience, and independently confirmed by `anti-pattern-report.txt`'s own `[unpaired-resource]` false-positive at the identical byte offset 48001 | accident | byte-exact edit: replace the single raw `0x00` byte with the two ASCII characters `\` `0` (the `\0` escape) — zero behavior change, same runtime string | `c96b787` | verified: `file(1)` now reports text, `git grep`/plain `grep` match inside the file, studio suite green (148/148) | + +## Notes + +- `node-compile-cache/`, `v8-compile-cache-1000/`, `gh-pages-dist/` are disk clutter but not + a tracked-artifact problem — left in place; deleting rebuildable local caches is out of this + loop's scope (nothing to commit, nothing a fresh clone would inherit). +- Zero accident rows remaining is the done-when for this ledger; the deliberate `dist/` row + now carries its reason and a verifiable sync-check (`pnpm sync-dist:check`). + +**Done 2026-07-05.** Zero accident rows remain; the one deliberate row (`dist/`) carries its +reason and a sync-check; the three generated rows are confirmed already `.gitignore`d. From aa02d0b878812a1a737286a77443fa7c2e9c6191 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:56:14 -0700 Subject: [PATCH 13/24] ci(checks): add typecheck/test/astro-check/gh-pages-build jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs on every push and on PRs targeting main. Four independent jobs so each check's pass/fail is visible separately in the PR UI: pnpm typecheck (all 6 packages), pnpm test (per-package vitest via --no-bail), astro check for apps/viewer, and a gh-pages-build verification (separate from deploy.yml's actual deploy build — catches build breaks on PRs, where deploy.yml never runs). Same Node 24 / pnpm 10 / LFS checkout as deploy.yml; deploy.yml itself untouched. --- .github/workflows/checks.yml | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 .github/workflows/checks.yml diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000..fb7fc844 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,104 @@ +name: Checks + +on: + push: + pull_request: + branches: [main] + +concurrency: + group: checks-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + typecheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - uses: pnpm/action-setup@v4 + with: + version: 10 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck every package + run: pnpm typecheck + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - uses: pnpm/action-setup@v4 + with: + version: 10 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run every package's test suite + # Per-package vitest (root vitest binary fails rune tests — never invoke it directly). + run: pnpm test + + astro-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - uses: pnpm/action-setup@v4 + with: + version: 10 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: astro check (apps/viewer) + run: pnpm --filter @archie/viewer run check + + gh-pages-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - uses: pnpm/action-setup@v4 + with: + version: 10 + + - uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build Studio + Viewer (verification only — deploy.yml owns the real deploy build) + run: bash scripts/build-gh-pages.sh From 2dfa0e17ac969b28ea3ae9fe18468c43ebcfec02 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:56:32 -0700 Subject: [PATCH 14/24] fix(studio): commit the tsconfig.json backing the typecheck script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created during the Issue 1 typecheck repair but never actually staged — the "typecheck" script added to package.json would have had nothing to run against on a fresh checkout/CI runner. --- apps/studio/tsconfig.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 apps/studio/tsconfig.json diff --git a/apps/studio/tsconfig.json b/apps/studio/tsconfig.json new file mode 100644 index 00000000..564a5990 --- /dev/null +++ b/apps/studio/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"] +} From cd421bc2554e148dc763600190fc4986ec5d4806 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 00:58:44 -0700 Subject: [PATCH 15/24] fix(viewer): generate .astro/types.d.ts before typecheck on a fresh checkout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit apps/viewer/tsconfig.json includes .astro/types.d.ts for the astro/client triple-slash reference that gives import.meta.env its type — but .astro/ is gitignored (generated) and only existed in local working dirs that had already run `astro dev`/`build`/`check` at least once. A fresh clone (any CI runner) had nothing to generate it, so `tsc --noEmit` failed on published.ts's import.meta.env access with "Property 'env' does not exist on type 'ImportMeta'" — caught by cloning into /tmp and re-running typecheck there rather than trusting the dirty working copy. Added a `pretypecheck` script (matching the existing predev/prebuild convention in this package) that runs `astro sync` first. --- apps/viewer/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/viewer/package.json b/apps/viewer/package.json index 18bd34cc..96288408 100644 --- a/apps/viewer/package.json +++ b/apps/viewer/package.json @@ -14,6 +14,7 @@ "preview": "astro preview", "test": "vitest run", "check": "astro check", + "pretypecheck": "astro sync", "typecheck": "tsc --noEmit" }, "dependencies": { From c0d9663493e746c724b4202991f4411ff3ec3a68 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:24:57 -0700 Subject: [PATCH 16/24] =?UTF-8?q?test(ci):=20trip=20typecheck=20red=20(del?= =?UTF-8?q?iberate)=20=E2=80=94=20reverted=20next=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/render-core/src/__ci_trip_typecheck.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages/render-core/src/__ci_trip_typecheck.ts diff --git a/packages/render-core/src/__ci_trip_typecheck.ts b/packages/render-core/src/__ci_trip_typecheck.ts new file mode 100644 index 00000000..93e09052 --- /dev/null +++ b/packages/render-core/src/__ci_trip_typecheck.ts @@ -0,0 +1,4 @@ +// Deliberate CI tripwire test (ISSUES.md Issue 1) — proves the typecheck job catches a real error. +// Reverted in the next commit. +const shouldBeAString: string = 12345; +export { shouldBeAString }; From 0cc23838b9eba132b6a9977883897982d1dab329 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:26:44 -0700 Subject: [PATCH 17/24] revert: remove typecheck tripwire (confirmed red in CI, checks.yml catches it) --- packages/render-core/src/__ci_trip_typecheck.ts | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 packages/render-core/src/__ci_trip_typecheck.ts diff --git a/packages/render-core/src/__ci_trip_typecheck.ts b/packages/render-core/src/__ci_trip_typecheck.ts deleted file mode 100644 index 93e09052..00000000 --- a/packages/render-core/src/__ci_trip_typecheck.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Deliberate CI tripwire test (ISSUES.md Issue 1) — proves the typecheck job catches a real error. -// Reverted in the next commit. -const shouldBeAString: string = 12345; -export { shouldBeAString }; From 531b60dda5adf051b408561f51022817e1a85cef Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:27:17 -0700 Subject: [PATCH 18/24] =?UTF-8?q?test(ci):=20trip=20test=20job=20red=20(de?= =?UTF-8?q?liberate)=20=E2=80=94=20reverted=20next=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/render-core/src/__ci_trip_test.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 packages/render-core/src/__ci_trip_test.test.ts diff --git a/packages/render-core/src/__ci_trip_test.test.ts b/packages/render-core/src/__ci_trip_test.test.ts new file mode 100644 index 00000000..cbbd56e5 --- /dev/null +++ b/packages/render-core/src/__ci_trip_test.test.ts @@ -0,0 +1,9 @@ +import { describe, it, expect } from "vitest"; + +// Deliberate CI tripwire test (ISSUES.md Issue 1) — proves the test job catches a real failure. +// Reverted in the next commit. +describe("CI tripwire", () => { + it("deliberately fails", () => { + expect(1).toBe(2); + }); +}); From 68835ea028595efd39837c4c14739e888f9cbca2 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:29:11 -0700 Subject: [PATCH 19/24] revert: remove test-job tripwire (confirmed red in CI, checks.yml catches it) --- packages/render-core/src/__ci_trip_test.test.ts | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 packages/render-core/src/__ci_trip_test.test.ts diff --git a/packages/render-core/src/__ci_trip_test.test.ts b/packages/render-core/src/__ci_trip_test.test.ts deleted file mode 100644 index cbbd56e5..00000000 --- a/packages/render-core/src/__ci_trip_test.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { describe, it, expect } from "vitest"; - -// Deliberate CI tripwire test (ISSUES.md Issue 1) — proves the test job catches a real failure. -// Reverted in the next commit. -describe("CI tripwire", () => { - it("deliberately fails", () => { - expect(1).toBe(2); - }); -}); From 237a10deb44cc446d4cca08e663cb93f406e362e Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:30:18 -0700 Subject: [PATCH 20/24] =?UTF-8?q?test(ci):=20trip=20astro-check=20job=20re?= =?UTF-8?q?d=20(deliberate)=20=E2=80=94=20reverted=20next=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/viewer/src/pages/__ci-trip-check.astro | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 apps/viewer/src/pages/__ci-trip-check.astro diff --git a/apps/viewer/src/pages/__ci-trip-check.astro b/apps/viewer/src/pages/__ci-trip-check.astro new file mode 100644 index 00000000..34b10154 --- /dev/null +++ b/apps/viewer/src/pages/__ci-trip-check.astro @@ -0,0 +1,5 @@ +--- +// Deliberate CI tripwire test (ISSUES.md Issue 1) — proves the astro-check job catches a real +// diagnostic that bare `tsc --noEmit` never sees (it doesn't parse .astro files). Reverted next commit. +--- +

{undefinedTripwireVariable}

From 91f58c1334d0051ccfb30987e103416b17b309ab Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:31:53 -0700 Subject: [PATCH 21/24] revert: remove astro-check tripwire (confirmed red in CI, checks.yml catches it) --- apps/viewer/src/pages/__ci-trip-check.astro | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 apps/viewer/src/pages/__ci-trip-check.astro diff --git a/apps/viewer/src/pages/__ci-trip-check.astro b/apps/viewer/src/pages/__ci-trip-check.astro deleted file mode 100644 index 34b10154..00000000 --- a/apps/viewer/src/pages/__ci-trip-check.astro +++ /dev/null @@ -1,5 +0,0 @@ ---- -// Deliberate CI tripwire test (ISSUES.md Issue 1) — proves the astro-check job catches a real -// diagnostic that bare `tsc --noEmit` never sees (it doesn't parse .astro files). Reverted next commit. ---- -

{undefinedTripwireVariable}

From a31959998c32d7d50d89405e3934a322ea1edcb5 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:32:41 -0700 Subject: [PATCH 22/24] =?UTF-8?q?test(ci):=20trip=20gh-pages-build=20job?= =?UTF-8?q?=20red=20(deliberate)=20=E2=80=94=20reverted=20next=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- archie.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archie.config.json b/archie.config.json index 116cc280..468d81f7 100644 --- a/archie.config.json +++ b/archie.config.json @@ -1,6 +1,6 @@ { "$comment": "THE single source for the canonical deploy origin (ADR-0013 + amendment). Everything that mints absolute URLs consumes this — Studio share/embed UI, viewer og/sitemap emitters, scripts/build-gh-pages.sh (via node -p). SITE_BASE / PUBLISH_BASE env vars override per deploy context but DEFAULT from here. Changing domains = edit this file only.", - "canonicalOrigin": "https://micahchoo.github.io/Archie/", + "canonicalOrigin": "https://example.com/__ci_trip_gh_pages_build/", "viewerPath": "viewer/", "studioPath": "studio/" } From e30c73624e61c454a23e77bc8d11ac9dec60fc84 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:35:13 -0700 Subject: [PATCH 23/24] revert: restore canonicalOrigin (confirmed gh-pages-build red in CI, checks.yml catches it) --- archie.config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archie.config.json b/archie.config.json index 468d81f7..116cc280 100644 --- a/archie.config.json +++ b/archie.config.json @@ -1,6 +1,6 @@ { "$comment": "THE single source for the canonical deploy origin (ADR-0013 + amendment). Everything that mints absolute URLs consumes this — Studio share/embed UI, viewer og/sitemap emitters, scripts/build-gh-pages.sh (via node -p). SITE_BASE / PUBLISH_BASE env vars override per deploy context but DEFAULT from here. Changing domains = edit this file only.", - "canonicalOrigin": "https://example.com/__ci_trip_gh_pages_build/", + "canonicalOrigin": "https://micahchoo.github.io/Archie/", "viewerPath": "viewer/", "studioPath": "studio/" } From bb3ed4b72c3c3ca53fc747e281025cdd5d550a07 Mon Sep 17 00:00:00 2001 From: Micah Date: Sun, 5 Jul 2026 01:37:00 -0700 Subject: [PATCH 24/24] =?UTF-8?q?docs:=20write=20ledgers/GATE.md=20?= =?UTF-8?q?=E2=80=94=20Issue=201=20CI=20tripwire=20ledger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ledgers/GATE.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 ledgers/GATE.md diff --git a/ledgers/GATE.md b/ledgers/GATE.md new file mode 100644 index 00000000..5e3e5296 --- /dev/null +++ b/ledgers/GATE.md @@ -0,0 +1,94 @@ +# GATE — CI tripwire ledger (ISSUES.md Issue 1) + +Inventory taken 2026-07-05 against `main` @ `2091557`. Node v24.14.0, pnpm 11.0.9 locally; +`deploy.yml` pins Node 24 / pnpm 10 — new checks job will match `deploy.yml`, not this machine. + +| check | command | local result | CI job | commit | +|---|---|---|---|---| +| render-core test | `pnpm --filter @render/core exec vitest run` | pass (688/688) | `test` | — | +| render-core typecheck | `pnpm --filter @render/core exec tsc --noEmit` | pass | `typecheck` | `ee244d8` | +| render-mount test | `pnpm --filter @render/mount exec vitest run` | pass (116/116) | `test` | — | +| render-mount typecheck | `pnpm --filter @render/mount exec tsc --noEmit` | pass | `typecheck` | `7415fe2`, `8693795` | +| render-svelte test | `pnpm --filter @render/svelte exec vitest run` | pass (7/7) | `test` | — | +| render-svelte typecheck | `pnpm --filter @render/svelte exec tsc --noEmit` | pass (cleared once render-mount's mount.ts:251 was fixed, as predicted) | `typecheck` | `7415fe2` | +| archie-viewer test | `pnpm --filter @render/archie-viewer exec vitest run` | pass (98/98) | `test` | — | +| archie-viewer typecheck | `pnpm --filter @render/archie-viewer exec tsc --noEmit` | pass (same cascade, same fix) | `typecheck` | `7415fe2` | +| viewer test | `pnpm --filter @archie/viewer exec vitest run` | pass (63/63) | `test` | — | +| viewer typecheck | `pnpm --filter @archie/viewer exec tsc --noEmit` | pass (needed `pretypecheck: astro sync` — see below) | `typecheck` | `cd421bc` | +| viewer astro check | `pnpm --filter @archie/viewer run check` | pass (0 errors/warnings/hints, 33 files) | `astro-check` | — | +| studio test | `pnpm --filter @archie/studio exec vitest run` | pass (148/148) | `test` | — | +| studio typecheck | `pnpm --filter @archie/studio exec tsc --noEmit` | pass — added `tsconfig.json` (extends root, `include: ["src"]`, no `rootDir`/`outDir` since `seed-data.ts` imports `apps/viewer/fixtures/*`) + `"typecheck": "tsc --noEmit"` script | `typecheck` | `8de4a8f`, `9a1aa33`, `7c05375`, `fb42311`, `2dfa0e1` | +| gh-pages build | `bash scripts/build-gh-pages.sh` | pass | `gh-pages-build` | — | + +CI wiring: `.github/workflows/checks.yml` (commit `aa02d0b`), 4 independent jobs, on every push + +PRs targeting main. `deploy.yml` untouched. Verified end-to-end via PR #1 (`ci/wire-checks`). + +## Tripped red — each job proven to catch a real defect (PR #1, `ci/wire-checks`) + +One deliberate defect planted per job, pushed, watched fail in both the push- and PR-triggered +Actions runs, then reverted — confirming each job actually gates on its class of failure and that +the four jobs are correctly isolated (a defect in one job's domain never fails the other three). + +| job | defect | trip commit | red confirmed | revert commit | +|---|---|---|---|---| +| `typecheck` | `const x: string = 12345` in a throwaway `render-core` file | `c0d9663` | yes (both runs) — `test`/`astro-check`/`gh-pages-build` stayed green | `0cc2383` | +| `test` | `expect(1).toBe(2)` in a throwaway `render-core` test | `531b60d` | yes (both runs) — other 3 jobs stayed green | `68835ea` | +| `astro-check` | undefined-variable reference in a throwaway `.astro` page (a diagnostic bare `tsc` never sees — confirmed locally: `astro check` exit 1, `tsc --noEmit` exit 0) | `237a10d` | yes (both runs) — other 3 jobs stayed green | `91f58c1` | +| `gh-pages-build` | corrupted `archie.config.json` `canonicalOrigin` to omit `/Archie/`, tripping the script's own explicit guard (confirmed locally first) | `a319599` | yes (both runs) — other 3 jobs stayed green | `e30c736` | + +Done: every check green on `ci/wire-checks` AND each witnessed failing exactly once. + +## Fresh-clone verification (not just the dirty working copy) + +Before trusting any of the above, cloned into `/tmp` and re-ran `pnpm install --frozen-lockfile` + +all 4 checks there. This caught a real bug the local working copy was masking: `apps/viewer`'s +typecheck depends on `.astro/types.d.ts` (the `astro/client` triple-slash reference that types +`import.meta.env`) — gitignored, astro-generated, and only present locally because `astro dev`/ +`build`/`check` had already been run here. A genuine fresh checkout (any CI runner) had nothing to +generate it, so `tsc --noEmit` failed on `published.ts`'s `import.meta.env` access. Fixed with a +`pretypecheck: astro sync` script (`cd421bc`, matching the existing predev/prebuild convention). +Re-verified clean on a second fresh clone after the fix. + +## Concurrent-session branch mishap (resolved) + +A second session was working ISSUES.md Issue 3/4 on the same checked-out working directory at the +same time. Both sessions' git commands share one `.git` — at some point the other session checked +out `main` mid-flow, so one of my commits (the deliberate typecheck-tripwire test, see below) landed +on local `main` instead of `ci/wire-checks`, and one of their commits landed on `ci/wire-checks` +instead of `main`. Resolved once the other session paused: reverted the tripwire commit off `main` +(non-destructive `git revert`, safe since `main` was never pushed with it) and reset the local+remote +`ci/wire-checks` branch back to its correct tip (`cd421bc`) — both stray commits were independently +verified safe to drop (one already an ancestor of `main`, the other byte-identical in content to a +commit already on `main`), and the reset/force-push was only done after explicit user authorization +naming the exact commits being overwritten. + +## Scope correction vs. ISSUES.md + +ISSUES.md's "known-red" list named only 3 sites (render-core x2, render-mount mount.ts:251). +Actual inventory found more: + +- **render-mount** also fails on ~20 pre-existing `noUncheckedIndexedAccess` / + `exactOptionalPropertyTypes` errors in `frame-overlay.test.ts`, `read-overlay-security.test.ts`, + `read-overlay.test.ts` — untouched by the mount.ts:251 fix, never mentioned in the issue. +- **render-svelte** and **archie-viewer** typecheck failures are *not* independent — both show the + identical single `mount.ts(251,43)` error, reached because `tsc` follows the imported source + graph even though neither package's own `include` covers `render-mount/src`. Fixing mount.ts:251 + once should clear both, pending re-verification. +- **studio** typechecking has never run before; a bare `tsc --noEmit` (matching every other + package's pattern) surfaces 22 errors on the first try, concentrated in `store.ts` (9 — looks + like a broken/incomplete type re-export, `RightsFields`/`MediaType`/etc. reported as + "cannot find name"), plus one real branded-type misuse in `publish-flows.svelte.ts` (×3, same + `LogicalId` cause), a `TileSourceDescriptor`/`Extentish` mismatch in `geo-notes.ts` (×4) + + its test (×1), and five one-off sites (`binding.ts`, `collab.test.ts`, `ingest-flows.ts`, + `save-queue.svelte.ts`, plus the `TileSourceDescriptor` overlap in `ingest-flows.ts`). + +Net: ~26 individual TypeScript error sites to clear across 3 packages before `pnpm -r typecheck` +is green — more than the 4 the issue named, none look architectural (no test asserts wrong +behavior), all look like mechanical strict-mode / branded-type fixes. + +## Tests are already green everywhere + +Every package's own `vitest run` passes today when invoked per-package (as above). The +"root vitest binary fails rune tests" problem noted elsewhere only bites the root `vitest` binary +run directly — `pnpm -r --no-bail test` (each package running its own local `vitest`) already +works and needs no fix. Issue 1's test-inventory step is done; nothing to repair there.