Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions docs/releases/1.0.0/readiness.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# 1.0.0 Readiness Record

Release decision: NOT READY
Source commit: branch `fix/1.0-export-integrity` (implementation commits e2c9dd3, 23e670a, 3098745, 064f518 on top of merged main 207a4d3)
Runtime: Node v24.16.0, npm 11.13.0, macOS 27.0 (arm64); Obsidian 1.13.7 installed (verified running); QA workspace: /var/folders/cg/8_2x8c9s5xx3dl1trdcs3ndh0000gn/T/document-exporter-1.0-qa.UgHjVD (temporary, retained until release verification)
Source commit: branch `acceptance/1.0-native-retry` (docs-only on top of merged main; executable bytes identical to main f0552fa plus description-string changes)
Runtime: Node v24.16.0, npm 11.13.0, macOS 27.0 (26A428); Obsidian 1.13.7 (Electron 39.2.6, Chromium 142.0.7444.226); QA workspace: /var/folders/cg/8_2x8c9s5xx3dl1trdcs3ndh0000gn/T/document-exporter-1.0-qa.UgHjVD (temporary, retained until release verification); native run evidence: …/native/run3-20260918 (executed 2026-09-18) and …/native/run4-20260918 (affected-case rerun after defect fixes)
Native harness: committed at `scripts/native-acceptance/` (CDP-driven, trusted renderer input; see its README for the two required environment accommodations)

| Gate | Status | Source commit / artifact SHA-256 | Evidence | Remaining action |
|---|---|---|---|---|
| Baseline | PASS | 2915687ebd656444054387fa474e0393bf420d7b | 2026-09-15 local run: `npm run check:version` ("Version metadata is consistent: 0.7.4"), `npm run lint:obsidian-warnings`, `npm run build`, `npm test` (20 files, 360 tests passed) — all exit 0. Remote read-only: 0 open issues, 0 open PRs; release 0.7.4 (published 2026-08-26) with `main.js`, `manifest.json`, `styles.css`; latest `verify` runs green including HEAD 2915687. No vault plugin symlink present, so builds cannot update a live plugin. | T0 complete |
| Output integrity | PASS | merged main 207a4d3 (PR #84, commit b44207c) | T1 reproduced the overwrite corruption as required (expected `[1]`, received `[2]` in `src/export/ExportIntegrity.test.ts`). T2 added directory isolation, exclusive writes (`wx` external / create-only vault), report-name protection and a 10-case regression matrix. Five export suites 145/145, full suite green, lint and build exit 0. | T6 reruns the two-run case through the native export dialog |
| Outcomes | PASS | e2c9dd3 (T3), 23e670a (T4) | `resolveExportStatus` state table (8 rows) plus 9 integration scenarios: early cancel, mid-batch cancel, cancel after render, second-source read failure (partial), PDF renderer rejection (failed), shared-attachment retry, missing input keeps original total, report-write failure stays completed-with-warning, unresolved-link-only stays completed. Runner finalizes through one path; `onFileComplete` reports completed count minus one. `exportResultMessage` distinguishes completed/partial/cancelled/failed for the UI. Full suite 411/411, lint and build exit 0. | Native dialog feedback wording checked in T6 (A08) |
| Headless artifacts | PASS | 3098745 | Fixture generator: 520 synthetic files, all manifest SHA-256 verified; second run refused non-empty destination; PNGs decode via macOS `sips` with matching dimensions (640x240, 160x100). Contract suite 10/10: Markdown/HTML-fallback/DOCX/EPUB content cases (markers, tables, code, XML validity, relationships, spine resolution, image byte equality, no `app://`), folder batch (nested primaries, relative links, shared attachment bytes), collision A→B, export-report name protection, missing-attachment and cancellation injections. `RELEASE_ARTIFACT_DIR` persistence verified with SHA-256 index (no PDF claims). Independent `unzip -t` passed on generated DOCX and EPUB. | Native artifact acceptance in T6 |
| Native artifacts | BLOCKED | candidate build main.js SHA-256 c0f73a64f49b59a37a4fc83668d45cc084fe0c1b1ec6a94168249a55e275bfdc (from main f0552fa) | 2026-09-17 session: tools installed and verified — OpenJDK 26 + EPUBCheck 5.2.1, LibreOffice 26.8.0.3 (~/Applications), Books/Preview present. Candidate installed into `/Users/Roger/my-vault`'s plugin directory and confirmed loaded in Obsidian 1.13.7 on macOS 27 (ribbon entry visible); 521 fixture files staged, then fully removed and the original plugin restored (main.js bc226ff2…) after the session. BLOCKED reason: the export dialog could not be driven by UI automation — one initial ribbon AXPress opened the modal, but select changes, Next/Export button presses, synthetic keys and coordinate clicks never reached the Electron DOM layer, and DOM context menus do not respond. A01-A12 were NOT executed; no native PASS is claimed. Supplementary real-tool checks of HEADLESS-generated artifacts (clearly not native evidence): EPUBCheck 5.2.1 `--failonwarnings` → 0 fatals/0 errors/0 warnings; LibreOffice headless conversion of the DOCX → clean PDF; `unzip -t` clean. | Human-driven or working-automation native session per protocol T6.2/T6.3 against the fixed candidate (tools are now installed); QA workspace retained at the recorded temporary path |
| Platforms | BLOCKED | Unmeasured | Only the macOS row of the T6.4 matrix is executable here, and it is blocked by the same dialog-automation gap above. Missing — Windows, Linux, iOS, Android environments and an isolated desktop Obsidian 1.4.0 install. None tested; no platform claim made. | Execute the bounded platform matrix on the required devices after the macOS interactive gap is closed |
| Documentation | IN PROGRESS | — | T7 executing 2026-09-17 with evidence-scoped content: descriptions/setting text are code-backed; the capability table cites headless-verified rows and marks native verification pending; the privacy paragraph is unchanged (A10 not run, per plan gating). | Capability table native columns and privacy wording finalize after T6 evidence |
| Output integrity | PASS | merged main 207a4d3 (PR #84, commit b44207c) | T1 reproduced the overwrite corruption as required (expected `[1]`, received `[2]` in `src/export/ExportIntegrity.test.ts`). T2 added directory isolation, exclusive writes (`wx` external / create-only vault), report-name protection and a 10-case regression matrix. Five export suites 145/145, full suite green, lint and build exit 0. | Native two-run case rerun executed in T6 (A04) — PASS |
| Outcomes | PASS | e2c9dd3 (T3), 23e670a (T4) | `resolveExportStatus` state table (8 rows) plus 9 integration scenarios: early cancel, mid-batch cancel, cancel after render, second-source read failure (partial), PDF renderer rejection (failed), shared-attachment retry, missing input keeps original total, report-write failure stays completed-with-warning, unresolved-link-only stays completed. Runner finalizes through one path; `onFileComplete` reports completed count minus one. `exportResultMessage` distinguishes completed/partial/cancelled/failed for the UI. Full suite 411/411, lint and build exit 0. | Native dialog feedback wording verified in T6 (A08) — PASS |
| Headless artifacts | PASS | 3098745 | Fixture generator: 520 synthetic files, all manifest SHA-256 verified; second run refused non-empty destination; PNGs decode via macOS `sips` with matching dimensions (640x240, 160x100). Contract suite 10/10: Markdown/HTML-fallback/DOCX/EPUB content cases (markers, tables, code, XML validity, relationships, spine resolution, image byte equality, no `app://`), folder batch (nested primaries, relative links, shared attachment bytes), collision A→B, export-report name protection, missing-attachment and cancellation injections. `RELEASE_ARTIFACT_DIR` persistence verified with SHA-256 index (no PDF claims). Independent `unzip -t` passed on generated DOCX and EPUB. | Native artifact acceptance executed in T6; the two defects it surfaced are fixed on this branch with regression tests added to this suite |
| Native artifacts | PASS (after defect fixes) | candidate main.js SHA-256 e371765a88e98f20af0e423f401367804d1ff3e315eefd37baacdceb14b3b18b, manifest f4d4268ae7a2b0aebd225e9831ac07ba4cf7ce7b8960de9354882ae11d97822b, styles f69c442f92e6a5ce3f4fc6caa43b65f1fef777c9f5dcb8ccf547174dc47bc264 (built from the fix commit on `acceptance/1.0-native-retry`; installed in `/Users/Roger/my-vault` per T6.1 for each run, original restored after) | 2026-09-18 third attempt closed the automation gap: root cause of prior BLOCKED state was macOS Obsidian defaulting to NATIVE (Electron) menus when `nativeMenus` is unset — invisible to both AX and DOM automation. CDP harness (trusted renderer input) executed all A01–A12 in real Obsidian against build 530550d9…: A01 five formats (markers, 中文/emoji, byte-identical images); A02 folder batch ×5 formats (nested paths kept); A03 selected files (excluded part absent, documented "Unresolved link" warning shown); A04 A→B→A (first-run bytes stable; reruns redirect to `<dest>-<timestamp>` siblings; red/blue image resolution correct); A05 explicit overwrite + vault source untouched; A06 report sentinel preserved + missing-reference diagnostics; A07 17-export expand/copy matrix (WANTED-SENTINEL only when expanded, EXCLUDED never, bounded cycle, copy=false → no assets but PDF keeps embedded image); A08 PDF mid-batch cancel 207/501 with accurate feedback and kept outputs (markdown batches finish before cancel lands — twice observed, recorded); A09 long PDF 22 pages with first/middle/last sentinels + DOCX complete; A10 loopback probe: preview 0, HTML export 3, PDF render 2, browser-open 2 requests — the export pipeline does fetch remote image URLs referenced in notes; A11 degradation recorded; A12 html-100 23s / md-501 1.9s / html-501 114s with "Large export: 501 files" warnings on both 501 runs. T6.3 independent tools: EPUBCheck 5.2.1 `--failonwarnings`; LibreOffice 26.8 opens all sampled DOCX (no repair dialog); `unzip -t` clean; PDFKit page/sentinel/page-render checks; Chrome headless renders. Two defects were found and FIXED on this branch: D1 — fallback converter emitted a bare `<li class="task">` (no `<ul>`), making any task-list note's EPUB invalid (EPUBCheck RSC-005; `src/formats/html-document.ts`); D2 — HTML batch exports wrote nested documents' attachment `src` relative to the batch root, breaking images in nested pages (`rewriteAppProtocolUrls` lacked the output-file context; the Markdown bundle was already correct). Regression tests added: EPUB chapter content-model check (every `li` inside a list, ☐/☑ glyphs), fallback HTML task-list structure, and per-file asset resolution at three nesting depths; full suite 413/413, lint and build exit 0. Affected native cases rerun in real Obsidian against the fixed build e371765a… (run4-20260918): A11 EPUB passes EPUBCheck `--failonwarnings` 0/0/0 with `<ul class="task-list"><li class="task">☐ Task item</li></ul>` in the chapter; A02/A03 HTML batches write `../assets/landscape.png` from nested pages and `assets/landscape.png` from root pages, and the nested page renders its image in Chrome (screenshot retained). Unaffected A-cases do not exercise the changed code paths (task-list conversion lives in the fallback renderer/EPUB chapters; the URL rewrite context only affects native HTML rendering), so their run3 evidence stands. Also recorded (not a defect): native-render batches crawl when the Obsidian window is backgrounded (Chromium timer throttling); rerun used the documented anti-throttling launch flags — foreground users unaffected. Prior-session cleanup corrected: the vault had still contained the run-2 candidate install and a typo'd workspace folder (`elease-acceptance-1.0-cu-20260917`); both removed, original plugin (main.js bc226ff2…) and `nativeMenus` config restored and hash-verified after every run. | None on macOS — remaining native scope is the non-macOS platform rows |
| Platforms | BLOCKED (macOS row executed) | macOS row: builds 530550d9… (full matrix) and e371765a… (affected-case rerun) | macOS + current stable Obsidian row executed 2026-09-18 (A01–A12 plus clean candidate install/enable/reload with version verified in-app; affected cases rerun after the defect fixes). Missing — Windows, Linux, iOS, Android environments and an isolated desktop Obsidian 1.4.0 install; none tested, no platform claim made for them. Harness is reusable on desktop platforms. | Execute the remaining bounded matrix rows on the required devices |
| Documentation | IN PROGRESS | — | T7 executed evidence-scoped: descriptions/setting text are code-backed; capability table cites headless-verified rows and marks native verification pending; privacy paragraph unchanged pending A10. A10 evidence now exists (see Native artifacts row): wording must not claim "no network requests" — observed behavior is that rendering/export fetches remote image URLs referenced in notes (loopback probe: preview 0, export 3, PDF 2, opened-HTML 2). | Finalize capability table native columns (now including the fixed task-list EPUB and nested HTML batch rows) and privacy wording from A10 observations |
| Release gate | PASS (local) | 064f518 | `scripts/check-version.mjs` extended to lockfile root and `versions.json`↔`minAppVersion` mapping; `node --test scripts/check-version.test.mjs` 8/8 (drift, missing entry, mapping mismatch, lockfile cases, wrong tag); `npm run check:version` OK; CI adds the script test before `check:version`; release workflow runs script test, version gate, lint, build, test before attestation and prefers `docs/releases/<tag>/release-notes.md`; both workflow files parse as valid YAML; CLAUDE.md release guidance updated. | None — CI verified the workflow changes on PR #85 (verify pass) |
| Upgrade / candidate | BLOCKED | Unmeasured | T9 not executed on 2026-09-17: the plan's bump prerequisite (T1-T8 complete, including initial native artifact/platform rows) is not met — native artifacts and platforms are BLOCKED. Per the plan, available work continued without a release-ready claim; no version bump, no tag, no `RELEASE_TAG` gate run. | Close the T6 interactive gap, rerun native/platform rows, then execute T9 (bump, final gates, install/upgrade smoke) |
| Published assets | BLOCKED | Unmeasured | Not published. T10 requires all required gates PASS and publication authorization; Native artifacts and Platforms are BLOCKED, so publication is refused by the plan's own rule ("Never publish with a required gate marked BLOCKED or FAIL"). | Resolve T6 native and platform rows (or an explicit, documented product-decision scope change by the owner), then authorize T10 |
| Upgrade / candidate | BLOCKED | Unmeasured | T9 not executed: the bump prerequisite (T1–T8 complete, native artifact/platform rows PASS) is not met — native artifacts is now PASS on macOS, but the non-macOS platform rows are unmeasured. | Close the remaining platform rows, then execute T9 (bump, final gates, install/upgrade smoke) |
| Published assets | BLOCKED | Unmeasured | Not published. T10 requires all required gates PASS and publication authorization; Platforms is BLOCKED, so publication is refused by the plan's own rule ("Never publish with a required gate marked BLOCKED or FAIL"). | Close platform rows (or an explicit, documented product-decision scope change by the owner), then authorize T10 |
62 changes: 62 additions & 0 deletions scripts/native-acceptance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Native acceptance harness (T6)

Drives the **real Obsidian app** through its export dialog to execute the
A01–A12 native acceptance cases from the 1.0.0 acceptance protocol, plus the
T6.3 artifact inspections with independent tools.

## How it works

Obsidian (Electron) is launched with `--remote-debugging-port`; a minimal CDP
client (`cdp.mjs`) talks to the renderer of the target vault window. All
interactions use **trusted renderer input** (`Input.dispatchMouseEvent`) and
real DOM events — the same code paths a user's clicks invoke. No mocks, no
spies; every export runs the actual plugin pipeline inside Obsidian.

## Two required environment accommodations

1. **DOM context menus.** macOS Obsidian defaults to *native* (Electron) menus
when the `nativeMenus` vault config is unset (`updateUseNativeMenu`:
`isMacOS && null => true`). Native menus are invisible to CDP, which is why
earlier OS-level automation attempts failed. `driver.useDomMenus()` sets
`nativeMenus: false` for the session; restore the prior value afterwards
(`restoreMenusConfig`).
2. **Background timer throttling.** Chromium throttles timers in background
windows to ~1/min. Native-renderer batches (HTML/PDF) crawl or appear hung
when the Obsidian window is in the background — a real user exporting with
the window visible does not hit this. Launch Obsidian with:

```
--remote-debugging-port=9223 \
--disable-background-timer-throttling \
--disable-backgrounding-occluded-windows \
--disable-renderer-backgrounding \
--disable-features=<app's own list>,IntensiveWakeUpThrottling
```

## Usage

```bash
# 1. Stage fixtures into the vault (scripts/create-release-fixtures.mjs)
# 2. Install the candidate plugin build per T6.1
# 3. Relaunch Obsidian with the flags above
# 4. Run cases (env vars override the default run workspace):
NATIVE_RUN_DIR=... NATIVE_VAULT_DIR=... NATIVE_STAGING_DIR=... \
node scripts/native-acceptance/run-a01-a06.mjs
node scripts/native-acceptance/run-a07-a12.mjs # A08/A12 reruns: run-a08-md.mjs, run-a12-retry.mjs
node scripts/native-acceptance/verify-a03-a04.mjs
# 5. Artifact inspections (EPUBCheck, LibreOffice, unzip, Chrome headless, PDFKit)
node scripts/native-acceptance/inspect-t63.mjs # swift pdf-inspect.swift used for PDFs
```

Case evidence is written as JSON under `$RUN/artifacts/`, screenshots under
`$RUN/screenshots/`, EPUBCheck reports under `$RUN/logs/`.

## Files

- `cdp.mjs` — minimal CDP client (targets, eval, trusted mouse input, screenshots)
- `driver.mjs` — Obsidian-specific driving (menus, export modal, notices, settings)
- `run-export.mjs` — shared case-runner utilities
- `run-a01-a06.mjs` / `run-a07-a12.mjs` — case execution
- `run-a08-md.mjs`, `run-a12-retry.mjs` — focused reruns
- `verify-a03-a04.mjs` — disk-state re-verification for A03/A04
- `inspect-t63.mjs`, `pdf-inspect.swift` — T6.3 independent tool checks
Loading