Skip to content

Commit 8fba5d1

Browse files
fix(import): page import previews like execution
Preview plans read the vault manifest through the same keyset-paged reader as execution, so manifests larger than one list page no longer make previews silently drop beyond-boundary rows; they are reported as missing like any other unseen source. Regression test seeds a real 10k-row manifest and fails against the unpaged reader (stash-verified).
1 parent c4dce8a commit 8fba5d1

3 files changed

Lines changed: 53 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ All notable changes to Engraphis are documented here. Format loosely follows
108108

109109
### Fixed
110110

111+
- Import previews now page the source manifest exactly like execution, so vaults whose manifest
112+
outgrew one list page (10k identities) no longer show manifest-only files as silently absent
113+
from the preview plan; beyond-boundary rows are reported as `missing` instead of dropped.
111114
- Importing more than 1,000 files through the dashboard no longer fails with "Internal Server
112115
Error": wizard upload routes parse multipart forms under the advertised 1,500-file ceiling
113116
instead of Starlette's hidden 1,000-part parser default, oversized batches return a clear 413,

engraphis/obsidian_import.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,9 @@ def _preview_manifest(
511511
scope=scope, memory_type=memory_type, strict_root=strict_root,
512512
)
513513
if manifest is None:
514-
items = self.store.list_source_import_items(vault_id=str(vault["id"]))
514+
# Page the manifest like import_scan does so previews on manifests
515+
# larger than one list page plan against the full item set.
516+
items, _ = self._all_source_items(vault_id=str(vault["id"]))
515517
else:
516518
items = [row for row in items if row.get("vault_id") == vault.get("id")]
517519
else:

tests/test_obsidian_service.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Real-service coverage for the owner-only Obsidian import facade."""
22
from __future__ import annotations
33

4+
import hashlib
45
import time
56

67
import pytest
@@ -43,6 +44,52 @@ def _import(service: MemoryService, files: list[tuple[str, bytes]], **kwargs) ->
4344
return started, _await_job(service, started)
4445

4546

47+
def test_preview_pages_the_full_manifest_like_execution():
48+
service = _service()
49+
try:
50+
started, imported = _import(
51+
service,
52+
[
53+
("A.md", b"# A\n"),
54+
("B.md", b"# B\n"),
55+
("C.md", b"# C\n"),
56+
],
57+
)
58+
vault_id = started["vault_id"]
59+
assert imported["state"] == "completed"
60+
61+
# Push the vault manifest past the default 10k list-page boundary with
62+
# filler identity rows that sort before the scan set, so an unpaged
63+
# preview loses exactly the rows a real oversized vault would lose.
64+
for i in range(10_001):
65+
service.store.upsert_source_import_item(
66+
vault_id=vault_id,
67+
source_key=hashlib.sha256(f"seed-{i}".encode()).hexdigest(),
68+
relative_path=f"0000-seed-{i:05d}.md",
69+
)
70+
71+
preview = service.preview_obsidian_upload(
72+
files=[("A.md", b"# A\n"), ("D.md", b"# D\n")],
73+
attachment_manifest=[],
74+
workspace="alpha",
75+
vault_label="Team notes",
76+
vault_id=vault_id,
77+
)
78+
79+
# An unpaged preview reads only the first list page, so manifest rows
80+
# beyond the boundary vanish from the report entirely. The paged reader
81+
# must surface every manifest row: A plans as unchanged and B/C — not
82+
# part of this preview's scan — are reported as missing, not dropped.
83+
statuses = {
84+
row["relative_path"]: row["status"] for row in preview["files"]
85+
}
86+
assert statuses["A.md"] != "missing"
87+
assert "B.md" in statuses
88+
assert "C.md" in statuses
89+
finally:
90+
service.close()
91+
92+
4693
def test_preview_is_write_free_and_service_enforces_confirmation_and_upload_guards(monkeypatch):
4794
service = _service()
4895
try:

0 commit comments

Comments
 (0)