Merge main into CouchDB cache compatibility changes

This commit is contained in:
vorotamoroz committed 2026-11-05 09:48:00 +00:00
commit c306146dcd
78 files changed
+6177 -929

No files matched your search

+16 -1
View File
@@ -230,6 +230,8 @@ Set `E2E_LIVESYNC_TARGET_ARTIFACT_ROOT` to the directory containing the exact re
Set `E2E_OBSIDIAN_INDEPENDENT_IDS=true` to run the same upload with E2EE, Path Obfuscation, and a separately derived ID key. The scenario verifies the local document and Chunk ID shapes before the Journal transfer.
Set `E2E_OBSIDIAN_CUSTOM_HTTP_HANDLER=true` when the local Object Storage fixture does not allow browser requests from Obsidian's renderer.
`test:e2e:obsidian:journal-nfc-resend` uses the same Object Storage variables with NFC path identity. Run `npm run test:e2e:obsidian:focused -- journal-nfc-resend --case all` for the plain and E2EE/Path Obfuscation cases with an independent ID key, or select `plain` or `encrypted`. It creates two conflict leaves with real Chunks with an exact shared ancestor, completes the initial upload, and deletes only its unique remote prefix while retaining the source database and populated transfer checkpoint. Rebuilding the remote must resend enough data for a fresh Obsidian Standard Fetch to recover both exact leaf bodies, Chunk references, revision IDs, and each leaf's `_revisions`. The source must retain its readable ancestor body. The receiver records whether that older body is available; ancestry IDs alone do not make a historical body readable. A full receiver restart must retain the same leaves, history, ancestor availability, and one NFC-equivalent physical control file. The restart consumes the saved settings and device state.
`test:e2e:obsidian:object-storage-setup-uri-workflow` uses the public Commonlib-backed tool to generate the initial Setup URI for a unique Object Storage prefix, completes visible initialisation on the first device, and then asks that working real Obsidian device to create a new Setup URI through the registered command. A second real Obsidian device imports only the device-generated URI. The workflow verifies the A-to-B note through explicit replication, then verifies that the B-to-A note arrives through `syncOnStart` after restarting the first device, without requesting manual replication. It captures the documented onboarding choices, and removes the Object Storage prefix only after both sessions have stopped. The test requires the current version marker and absence of a compatibility pause after Fetch and after restarting the same Vault, without accepting a review automatically.
`test:e2e:obsidian:object-storage-qr-workflow` runs the same Object Storage round trip with QR settings on the second device. It takes the first device's settings, assigns a distinct database suffix in the QR fixture, encodes them with Commonlib's QR encoder, passes the payload to the real QR decoding entry point, and selects **Join this device** in the visible dialogue. Unlike the Setup URI, the QR payload includes a database suffix; explicitly choosing one makes the namespace change independent of Obsidian's initial defaults. Before Fetch begins, the scenario verifies that the imported namespace has its current compatibility marker without a pause. Fetch then selects the receiving device's own suffix when resetting the local database. The test verifies the marker and absence of a pause again after Fetch and after a natural restart. It covers the QR settings and setup flow, without requiring a camera or exercising operating-system URI dispatch.
@@ -244,6 +246,12 @@ The P2P Setup URI workflow also schedules another Fetch and injects an exception
`test:e2e:obsidian:p2p-connection-check` owns the browser-to-Obsidian preflight path. It serves the WebPeer production build from loopback, asks the page to generate a disposable Setup URI using the local relay, starts its browser reference peer, and applies that exact URI through visible onboarding in an isolated empty real Obsidian Vault. After the first successful WebRTC diagnostic appears, it selects the action for another device in the same room, proves that the Setup URI was not regenerated, applies it to a second isolated empty real Obsidian Vault, and requires both the successful total and the baseline number of simultaneous active connections to advance. It captures the result card without Setup URI credentials and does not claim to verify note synchronisation. Run `test:e2e:obsidian:p2p-connection-check:services` to build both production artefacts and let the scenario start and stop the Compose relay.
`test:e2e:obsidian:p2p-nfc` runs the plain case and the E2EE case using Path Obfuscation and an independent ID key, serially, in an isolated Compose project with a local signalling relay and two real Obsidian processes at a time. Each case seeds an NFD-named source file, fetches it by its NFC spelling, and compares the real local Metadata ID, exact body, and referenced Chunks on both peers. It edits the note from the receiving peer, verifies that the Metadata ID remains stable and that the original revision body remains readable, then fully stops and relaunches the same Vault to verify the ID, updated body, original revision, and a further transfer after restart. A fresh path version 0 peer must show the visible P2P compatibility refusal; the test verifies that it receives no source Metadata and retains its local sentinel. Run `npm run test:e2e:obsidian:p2p-nfc -- --case plain` or `-- --case encrypted` to select one case for debugging. The host wrapper builds the plug-in, uses the existing extracted Obsidian directory and its `obsidian-cli`, mounts the repository read-only, and tears down its unique Compose project after the run. It does not download Obsidian or npm dependencies.
Each P2P case also transfers another Unicode note after restart, renames it on the receiving peer, compares the new Metadata IDs and exact content, and verifies deletion on both peers.
Add `-- --migration` to start with legacy databases and exercise source Rebuild followed by receiving-device Standard Fetch. Because Obsidian's file cache normalises names, the scenario seeds valid legacy NFD Metadata IDs using the real stored Chunks before reconstruction. It verifies replacement of those IDs, physical NFD-name retention, ordinary legacy-peer refusal, and successful migration after a source restart. It also attempts Fetch with mismatched settings, verifies the local database is reset before peer refusal while the physical note remains intact, then retries with NFC and verifies convergence. The migration phase calls the running plug-in's production Rebuild and Fetch methods and uses real peer selection; reservation through the settings dialogue has separate coverage.
`test:e2e:obsidian:startup-scan` starts from a CouchDB fixture using current settings with its device-local compatibility marker already acknowledged, stops Obsidian, writes a note directly into the Vault, restarts the same isolated Vault and profile without rewriting its plug-in data, and verifies from CouchDB that the start-up scan picked up the offline file. Onboarding remains covered by `onboarding-invitation`; this scenario owns the ordinary configured restart and start-up scan.
`test:e2e:obsidian:partial-startup-file-failure` is a focused Linux release-acceptance scenario for an ordinary configured restart. It stores one valid database-only note and one database-only note whose path component is 258 UTF-8 bytes, then restarts the same isolated Vault and profile. On a Linux test Vault which enforces the conventional 255-byte component limit, the scenario requires the valid file to be reflected, the application to become ready, the partial-failure Notice to appear, and the failed path to remain readable and eligible for a later scan with its exact path in the verbose log. It remains outside `local-suite` because the failure fixture is deliberately platform-specific.
@@ -264,7 +272,9 @@ The workflow creates a random dedicated database, records only SHA-256 Seed fing
This proves in real Obsidian the plug-in behaviour shared by supported platforms, including the encrypted bidirectional round-trip and protection against a stale client restoring the old remote Seed. It does not verify iPadOS-specific background or reconnect lifecycle behaviour, and it does not count as Android device evidence. The workflow remains outside `test:e2e:obsidian:local-suite` because it is a focused release-acceptance check.
`test:e2e:obsidian:conflict-dialog-policy` creates three real local revision leaves without a remote service and opens the pairwise merge dialogue in Obsidian. It verifies the three-version count, requires the four decision buttons to be stacked vertically, concatenates the displayed pair as a child of the displayed winner, confirms that the untouched leaf remains as one conflict, postpones that remaining pair, restarts the same isolated Vault and profile, and confirms that only the two current versions are reconstructed. It also verifies that an ordinary repeated conflict check does not reopen a postponed dialogue, that **Resolve if conflicted.** explicitly reopens it, and that the active editor retains the appropriate unresolved-conflict warning. The scenario then invokes the same Commonlib consumer boundary used for an incoming replicated document and checks that a postponed warning disappears, an open stale dialogue closes, and the conflict-processing queue completes even when the dialogue closes immediately. This isolates the Obsidian UI contract from transport and second-device setup. The fixture owns one temporary Vault and profile, and the session runner stops Obsidian before removing them.
`test:e2e:obsidian:conflict-dialog-policy` creates three real local revision leaves without a remote service and opens the pairwise merge dialogue in Obsidian. It verifies the three-version count, requires the four decision buttons to be stacked vertically, concatenates the displayed pair as a child of the displayed winner, confirms that the untouched leaf remains as one conflict, postpones that remaining pair, restarts the same isolated Vault and profile, and confirms that only the two current versions are reconstructed. It also verifies that an ordinary repeated conflict check does not reopen a postponed dialogue, that **Resolve if conflicted.** explicitly reopens it, and that the active editor retains the appropriate unresolved-conflict warning. The scenario then invokes the same Commonlib consumer boundary used for an incoming replicated document and checks that a postponed warning disappears, an open stale dialogue closes, and the conflict-processing queue completes even when the dialogue closes immediately. This isolates the Obsidian UI contract from transport and second-device setup. The fixture owns one temporary Vault and profile, and the session runner stops Obsidian before removing them. Its unload check requires the queue to report cancellation, closes active and waiting dialogues, and compares Vault contents, conflict leaves, and revision ancestry after reload.
`test:e2e:obsidian:log-lifecycle` delays the local database close and tests both successful and failed shutdown. It verifies that logs remain available during shutdown, that later logs go to the console after display subscriptions are released, and that logs from the previous instance do not reach the reloaded instance. It uses an isolated Vault and profile without a remote service.
`test:e2e:obsidian:revision-repair` creates an ordinary healthy logical deletion and two current leaf revisions in a temporary real Obsidian Vault, then removes a chunk used only by the non-winning revision. It proves that automatic conflict checking does not discard the unreadable branch, and that a healthy logical deletion with no Vault file is neither reported nor retained as Vault provenance. **Inspect conflicts and file/database differences** must show the winner and conflict separately, identify the exact unreadable revision and missing chunk, show the compact `Δsize` and `Δtime` diagnostics, and expose a wrench menu with the appropriate actions for each branch. The scenario opens the existing comparison dialogue in read-only mode, applies the readable winner to the Vault, shows the compact matching-winner and remaining-conflict status, records the exact winner as Vault provenance without creating a child, and confirms that retrying the unreadable branch leaves the revision tree unchanged. It then verifies both the cancellation path and the explicit confirmation path for discarding only that selected current branch, requires the winner and its Vault provenance to remain unchanged, and captures the repair card, a 360-pixel-wide reflow check, the matching-winner status, both revision menus, and the read-only comparison. The narrow capture checks responsive layout, not a mobile operating-system lifecycle. The scenario uses no remote service; a retry is therefore expected to remain unreadable unless the chunk is already available locally.
@@ -404,6 +414,11 @@ When these checks pass for the release artefacts, BRAT acceptance can be limited
- `E2E_OBSIDIAN_REVIEW_HARNESS_TIMEOUT_MS`: timeout for Review Harness view and action boundaries; default is 15 seconds.
- `E2E_OBSIDIAN_P2P_PANE_TIMEOUT_MS`: timeout for the P2P status pane and its principal connection control; default is 10 seconds.
- `E2E_OBSIDIAN_P2P_WORKFLOW_TIMEOUT_MS`: timeout for each visible P2P Setup URI, peer-discovery, approval, and replication control; default is 60 seconds.
- `E2E_OBSIDIAN_P2P_NFC_TIMEOUT_MS`: timeout for P2P NFC transfers and the incompatible-peer refusal; default is 120 seconds.
- `E2E_OBSIDIAN_P2P_NFC_UI_TIMEOUT_MS`: timeout for P2P NFC status and setup controls; default is 60 seconds.
- `E2E_P2P_NFC_KEEP_ARTIFACTS=1`: retain successful Compose screenshots and diagnostics; failures are always retained.
- `E2E_P2P_NFC_CASE`: case selected by the Compose wrapper (`all`, `plain`, or `encrypted`); default is `all`. The `--case` option overrides this value.
- `E2E_P2P_NFC_OBSIDIAN_DIR`: extracted Linux Obsidian directory mounted into the Compose runner. The wrapper normally infers it from the discovered `OBSIDIAN_BINARY` and requires the corresponding `obsidian-cli` in the same directory.
- `E2E_P2P_CHECK_CONNECTION_TIMEOUT_MS`: timeout for the browser-to-Obsidian successful WebRTC diagnostic; default is 60 seconds.
- `E2E_P2P_CHECK_SCREENSHOT`: explicit path for the successful browser result screenshot; default is `p2p-connection-check-browser-success.png` under `E2E_OBSIDIAN_DIAGNOSTICS_DIR`.
- `E2E_P2P_RELAY_URL`: signalling relay used by the real-Obsidian P2P workflow; default is the local relay at `ws://127.0.0.1:4010/`.