From f43c5e4315502aebdf476d161154e4fbb3fe73ba Mon Sep 17 00:00:00 2001 From: DTALEX66 Date: Sun, 9 Aug 2026 13:55:26 +0800 Subject: [PATCH 1/3] docs: align current release status --- README.md | 2 +- docs/PROJECT_STATUS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ba3e72..4d755fe 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Research → Evidence → Knowledge → Learning | Phase 5–6 | Knowledge/Learning 与 Enhancement 闭环 | ✅ candidate 治理闭环完成 | 审批、版本、弃用与 provenance 边界已验证 | | Phase 7–8 | 受限 Planner tracer、多维 Evaluation、Sleep Loop 构件 | 🟡 首条纵向 tracer 完成 | `read file:`、Permission、Evidence、Evaluation 与 Lesson 已验证;通用 Planner 和统一执行端口未完成 | | Phase 9 | Contract & Tracer Alpha | ✅ 历史合同/追踪基线完成 | 不等于完整产品 Alpha,也不证明公开 release | -| Product Stage A0 | 产品真相、诊断、媒体摄入与发布门禁 | 🟡 收口中 | Job/Outbox/OCR 基线、按需 dispatcher、本地真实 Chromium delivery gate 与 Windows/NSIS 门禁已验证;Tauri WebView 点击级证据、ASR、公开发布资产仍待完成 | +| Product Stage A0 | 产品真相、诊断、媒体摄入与发布门禁 | 🟡 收口中 | Job/Outbox/OCR 基线、按需 dispatcher、本地真实 Chromium delivery gate、Windows/NSIS 门禁与公开 `v0.5.0` 资产已验证;Tauri WebView 点击级证据、ASR、签名发布与更高阶用户交互仍待完成 | ### 当前里程碑:Product Stage A0 真相基线 diff --git a/docs/PROJECT_STATUS.md b/docs/PROJECT_STATUS.md index da321e6..f814b08 100644 --- a/docs/PROJECT_STATUS.md +++ b/docs/PROJECT_STATUS.md @@ -1,6 +1,6 @@ # 项目当前状态 -> 更新:2026-08-08。本页是能力状态入口;旧审计文件是历史快照。机器无关的恢复检查见 [`HANDOFF_2026-07-21.md`](HANDOFF_2026-07-21.md),实时分支、SHA、dirty 状态与 CI 必须从 Git/GitHub 读取。 +> 更新:2026-08-09。本页是能力状态入口;旧审计文件是历史快照。机器无关的恢复检查见 [`HANDOFF_2026-07-21.md`](HANDOFF_2026-07-21.md),实时分支、SHA、dirty 状态与 CI 必须从 Git/GitHub 读取。 ## 发布真相 From 94fc13ac930c7b2858ecbc2101911e4301cead13 Mon Sep 17 00:00:00 2001 From: DTALEX66 Date: Sun, 9 Aug 2026 13:59:06 +0800 Subject: [PATCH 2/3] docs: clarify desktop release evidence boundary --- workspace/intake/022_windows_desktop_shell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspace/intake/022_windows_desktop_shell.md b/workspace/intake/022_windows_desktop_shell.md index 0408496..ee3bbd7 100644 --- a/workspace/intake/022_windows_desktop_shell.md +++ b/workspace/intake/022_windows_desktop_shell.md @@ -33,4 +33,4 @@ Tauri Windows CI 在生成 NSIS 后必须真实执行安装、启动、Workspace HTTP、正常关闭、强制终止进程树、字节码零增长和卸载零残留验证;仅检查 EXE 文件存在不能作为安装闭环证据。 -当前 Release Manifest 仍保持 `unreleased`、`public=false`。未签名安装器只用于本地 Alpha 验证,不能作为公开发行或已建立发布身份的证据。 +当前源码 Release Manifest 仍保持 `unreleased`、`public=false`;这不否定已独立验证的公开 `v0.5.0` artifact identity、资产 checksum 与 installer lifecycle。当前没有签名发布声明;后续未签名构建仍不能自动作为新的公开发行证据。 From 91f5f1518da8cbfc879a991249d77fba6d9bc219 Mon Sep 17 00:00:00 2001 From: DTALEX66 Date: Sun, 9 Aug 2026 14:08:49 +0800 Subject: [PATCH 3/3] fix(ingestion): include markitdown PDF runtime dependencies --- app/release-manifest.json | 2 +- pyproject.toml | 4 +- tests/test_adapter_contract.py | 28 ++++++++++++++ uv.lock | 70 ++++++++++++++++++++++++++++++++-- 4 files changed, 97 insertions(+), 7 deletions(-) diff --git a/app/release-manifest.json b/app/release-manifest.json index 2d1eca1..f01792f 100644 --- a/app/release-manifest.json +++ b/app/release-manifest.json @@ -24,7 +24,7 @@ "dependency_lock": { "path": "uv.lock", "algorithm": "sha256", - "digest": "e103c5f9a46ca2e11d50460b610de648978b62e60f53bdd7dd97d81fcf121cf8", + "digest": "9916e6dba6d152cff045abf188218a0a3a533a786b3c3061738dc3a128aa4268", "format_version": 1, "revision": 4 }, diff --git a/pyproject.toml b/pyproject.toml index 61e2f79..4c2f508 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ dependencies = [ "sqlite-vec>=0.1.6", "loguru>=0.7", "structlog>=24.0", - "markitdown>=0.1", + "markitdown[pdf]>=0.1", "trafilatura>=1.6", "networkx>=3.0", "litellm==1.91.0", @@ -61,7 +61,7 @@ ci = [ "uvicorn[standard]>=0.22", ] ci-adapters = [ - "markitdown>=0.1", + "markitdown[pdf]>=0.1", "newspaper4k>=0.9", "readabilipy>=0.3", "trafilatura>=1.6", diff --git a/tests/test_adapter_contract.py b/tests/test_adapter_contract.py index 571778c..0138a32 100644 --- a/tests/test_adapter_contract.py +++ b/tests/test_adapter_contract.py @@ -351,6 +351,34 @@ def test_pdf_uses_markitdown(self, tmp_path): assert "Markdown in a" in content assert engine == "markitdown" + def test_real_pdf_uses_markitdown_pdf_extra(self, tmp_path): + """A structurally valid PDF reaches the installed PDF extra.""" + from app.ingestion.multi_format import convert_file + + objects = [ + b"1 0 obj<< /Type /Catalog /Pages 2 0 R >>endobj", + b"2 0 obj<< /Type /Pages /Kids [3 0 R] /Count 1 >>endobj", + b"3 0 obj<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R >>endobj", + b"4 0 obj<< /Length 0 >>stream\n\nendstream\nendobj", + ] + body = b"%PDF-1.4\n" + offsets = [0] + for obj in objects: + offsets.append(len(body)) + body += obj + b"\n" + xref = len(body) + body += b"xref\n0 5\n0000000000 65535 f \n" + body += b"".join(f"{offset:010d} 00000 n \n".encode() for offset in offsets[1:]) + body += b"trailer<< /Size 5 /Root 1 0 R >>\nstartxref\n" + body += str(xref).encode() + b"\n%%EOF\n" + + pdf = tmp_path / "real.pdf" + pdf.write_bytes(body) + content, engine = convert_file(pdf) + + assert isinstance(content, str) + assert engine == "markitdown" + def test_html_uses_trafilatura(self, tmp_path): """HTML uses trafilatura when installed.""" from app.ingestion.multi_format import convert_file diff --git a/uv.lock b/uv.lock index 8cee34e..b49aa8d 100644 --- a/uv.lock +++ b/uv.lock @@ -627,7 +627,7 @@ dependencies = [ { name = "fastapi" }, { name = "litellm" }, { name = "loguru" }, - { name = "markitdown" }, + { name = "markitdown", extra = ["pdf"] }, { name = "networkx" }, { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, @@ -698,7 +698,7 @@ ci = [ { name = "uvicorn", extra = ["standard"] }, ] ci-adapters = [ - { name = "markitdown" }, + { name = "markitdown", extra = ["pdf"] }, { name = "newspaper4k" }, { name = "readabilipy" }, { name = "trafilatura" }, @@ -716,7 +716,7 @@ requires-dist = [ { name = "langfuse", marker = "extra == 'ingestion'", specifier = ">=4.0" }, { name = "litellm", specifier = "==1.91.0" }, { name = "loguru", specifier = ">=0.7" }, - { name = "markitdown", specifier = ">=0.1" }, + { name = "markitdown", extras = ["pdf"], specifier = ">=0.1" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.8" }, { name = "networkx", specifier = ">=3.0" }, { name = "numpy", specifier = ">=1.24" }, @@ -767,7 +767,7 @@ ci = [ { name = "uvicorn", extras = ["standard"], specifier = ">=0.22" }, ] ci-adapters = [ - { name = "markitdown", specifier = ">=0.1" }, + { name = "markitdown", extras = ["pdf"], specifier = ">=0.1" }, { name = "newspaper4k", specifier = ">=0.9" }, { name = "readabilipy", specifier = ">=0.3" }, { name = "trafilatura", specifier = ">=1.6" }, @@ -2030,6 +2030,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/30/8031f183ee86ea8ac4e7ea1296bab4cca1bee2fd036a26df69764eb7ca74/markitdown-0.1.6-py3-none-any.whl", hash = "sha256:07b2d5bf87b5c53e13a9f2fdc440df8ccc85e26f40c1e557781727b700049775", size = 70032, upload-time = "2026-05-26T22:44:03.209Z" }, ] +[package.optional-dependencies] +pdf = [ + { name = "pdfminer-six" }, + { name = "pdfplumber" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -2669,6 +2675,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, ] +[[package]] +name = "pdfminer-six" +version = "20260107" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "charset-normalizer" }, + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/a4/5cec1112009f0439a5ca6afa8ace321f0ab2f48da3255b7a1c8953014670/pdfminer_six-20260107.tar.gz", hash = "sha256:96bfd431e3577a55a0efd25676968ca4ce8fd5b53f14565f85716ff363889602", size = 8512094, upload-time = "2026-01-07T13:29:12.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/8b/28c4eaec9d6b036a52cb44720408f26b1a143ca9bce76cc19e8f5de00ab4/pdfminer_six-20260107-py3-none-any.whl", hash = "sha256:366585ba97e80dffa8f00cebe303d2f381884d8637af4ce422f1df3ef38111a9", size = 6592252, upload-time = "2026-01-07T13:29:10.742Z" }, +] + +[[package]] +name = "pdfplumber" +version = "0.11.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pdfminer-six" }, + { name = "pillow" }, + { name = "pypdfium2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/56/6f450312ba05a27d7713b73857c1a25100dbda04fbc1331b13fb227a607d/pdfplumber-0.11.10.tar.gz", hash = "sha256:b95b2d28c66efb0a794a83b88c6c6aea5987532a445d20a1cbcfa657022e6e57", size = 102892, upload-time = "2026-06-15T03:31:31.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/9a/07d658e1e7fad860f1c541ab941348125dbdab773be3a0afaf32361866c7/pdfplumber-0.11.10-py3-none-any.whl", hash = "sha256:7741ea81bf165b474b153e6789d10d18e06b6ddcf3ec84289c3ef2fed6802580", size = 60047, upload-time = "2026-06-15T03:31:29.702Z" }, +] + [[package]] name = "pillow" version = "12.3.0" @@ -3161,6 +3194,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/18/1dd71c9b43192ab83f1d531ad6002dc81108ac36c475f79fb7a295abe2f4/pyopenssl-26.3.0-py3-none-any.whl", hash = "sha256:46367f8f66b92271e6d218da9c87607e1ef5a0bc5c8dea5bb3db82f395c385a3", size = 56008, upload-time = "2026-06-12T20:28:05.999Z" }, ] +[[package]] +name = "pypdfium2" +version = "5.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/42/0b51bdf50ccf13f3deb3209ca996179a49761dc191748469cf0de55b0055/pypdfium2-5.12.1.tar.gz", hash = "sha256:d0e0648fb2e28f50efcd1ec0a5a18ced9f4d66b2c227fae9b603f0a883b2d13f", size = 274428, upload-time = "2026-07-17T10:01:22.713Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/09/7e/bd8df53b1131c582f6646372047b49162032bd01628d49b9a60cd94d2181/pypdfium2-5.12.1-py3-none-android_23_arm64_v8a.whl", hash = "sha256:05bab9b1ba2de7fc299ae2af25cb9c8a0543bc8bb893e879fe8c9ba8310e9ce4", size = 3392276, upload-time = "2026-07-17T10:00:47.376Z" }, + { url = "https://files.pythonhosted.org/packages/b2/13/a2b71e17b0439d2af78c817a381e3557371c6c56098581da8485aef65ea6/pypdfium2-5.12.1-py3-none-android_23_armeabi_v7a.whl", hash = "sha256:d4ee061e566a6422b660cdddaaa799a2d1cbf2f016921bcaf24d61426d01d942", size = 2848776, upload-time = "2026-07-17T10:00:49.09Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a8/d7a61700db3022792b28bce5264be90a7d2e7104998362af6b93766f50b2/pypdfium2-5.12.1-py3-none-macosx_13_0_arm64.whl", hash = "sha256:66a9ed40d70a5d728cd42148fecb9d7a0917c6161d6bb67c844093a4ed1df089", size = 3480243, upload-time = "2026-07-17T10:00:50.674Z" }, + { url = "https://files.pythonhosted.org/packages/01/2c/d7a38fad74b6da0947cf8763aee0f8e6c9d3c12fc8e137aa615f7f8ae76c/pypdfium2-5.12.1-py3-none-macosx_13_0_x86_64.whl", hash = "sha256:847378a5ab41332998b2621b21bab2e96dc8c3eff36a08bce26695b964163983", size = 3643490, upload-time = "2026-07-17T10:00:52.236Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/aca739676323558595fcf8cdc8d7939d2b25aaaa6f538e829f1fee938cdd/pypdfium2-5.12.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eabf028ad8e7bc7811c9acf3a72718c180569b624b844d2c6cc974609784275", size = 3649734, upload-time = "2026-07-17T10:00:53.776Z" }, + { url = "https://files.pythonhosted.org/packages/a4/e0/e4ecc05f4f1a11d11c8d684a24b2fc8be8207f341be985dac301caa4f6aa/pypdfium2-5.12.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7857cfa6642ec5a09db12ff8f5cf6b6494585b5e3a605399fddc4fb862837b63", size = 3380828, upload-time = "2026-07-17T10:00:55.377Z" }, + { url = "https://files.pythonhosted.org/packages/17/1b/c94c9d486791276e736350917a11fe2cf3acba2c6c7f03f9ac0d51f8952a/pypdfium2-5.12.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05bfa20a08a96584253bbe38b60e13f81a037eac31c5579e607ec1480ad25dbf", size = 3777202, upload-time = "2026-07-17T10:00:57.212Z" }, + { url = "https://files.pythonhosted.org/packages/14/aa/7f81f0c035fc32850dfab9daf78530814f215be226dad7491e3caa0a3e8c/pypdfium2-5.12.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9f059f7bdbdf4352eb83691071096940d769d6ae5930b8734237fdb1bd78fbc2", size = 4186083, upload-time = "2026-07-17T10:00:59.022Z" }, + { url = "https://files.pythonhosted.org/packages/23/16/21420a6f2bc5f981299c336817dd5d72709dad5fda30ac38cbd5f0f7b372/pypdfium2-5.12.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e10cbf41b21233ec5e20adfc170cf60edd77abead86a97dc708fff55a8a886c7", size = 3701734, upload-time = "2026-07-17T10:01:00.952Z" }, + { url = "https://files.pythonhosted.org/packages/36/a1/bb89f49e2b3ea3e945b67859d2ec6e73e722a83c006099c675692641e51d/pypdfium2-5.12.1-py3-none-manylinux_2_27_s390x.manylinux_2_28_s390x.whl", hash = "sha256:07eeebb2784f4cd38d386b924235df43217a397442796673296bb6efbdaad1d0", size = 4030403, upload-time = "2026-07-17T10:01:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/80/a7/cea5eb0c39e9c6fdf9853a3008bf021d08f962228073af90354b60c5ccdc/pypdfium2-5.12.1-py3-none-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5c3e6cbe43581af79526184643920ab03a9401a0c79f2226bea9d4d1e3d34008", size = 3994411, upload-time = "2026-07-17T10:01:04.25Z" }, + { url = "https://files.pythonhosted.org/packages/fc/43/5e470213b27c13b0d94d03d97fc3740507edadea1d1e2ce2049bfbec4aa0/pypdfium2-5.12.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4648f0905441bcb141687ca2263bbf38a1aa056b943eef06019f91cff3e1da4a", size = 4993687, upload-time = "2026-07-17T10:01:05.811Z" }, + { url = "https://files.pythonhosted.org/packages/db/da/af7972ca72f24ed720db6501333fd67bc66aa6aa5a5ec698551bd30ae62e/pypdfium2-5.12.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:bdff622181fab64f32328591c9c8287cdc745c9a1f2afc26ca3feba39e3e6645", size = 4534560, upload-time = "2026-07-17T10:01:07.291Z" }, + { url = "https://files.pythonhosted.org/packages/a9/63/06a7f2cd691f7e336cbc53fd65453fee516042c8ddb016bc50d1cd2bed45/pypdfium2-5.12.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:236dbdc88aa54f14b27937ccb2ebe3dcf08c10dbb8652f432ea982dc9af39732", size = 5237681, upload-time = "2026-07-17T10:01:08.997Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f5/937b080671758ab0b3d3d69b2657006682e4c6a0134b36774be4ed1afcfb/pypdfium2-5.12.1-py3-none-musllinux_1_2_ppc64le.whl", hash = "sha256:9c8856ce7dd77a7827476c7d75afe1197d6cd505f5cb4167b6aacf661f3f8ea5", size = 5143027, upload-time = "2026-07-17T10:01:10.69Z" }, + { url = "https://files.pythonhosted.org/packages/32/02/094632700c24728fa443dc89d9d1c6e4fc05bb00778b22e8482fdb133da0/pypdfium2-5.12.1-py3-none-musllinux_1_2_riscv64.whl", hash = "sha256:5f257bb40fa44ce9ba18d2c919777dbd3f16bf22548b1d68fd56c7c92f1de530", size = 4647048, upload-time = "2026-07-17T10:01:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d0/12d84bf55a4fcf2c0ed242afc94168933194f672067e1d162aa60a8e4426/pypdfium2-5.12.1-py3-none-musllinux_1_2_s390x.whl", hash = "sha256:974082344172da76a5c3c0782eaedfe6069dbe88db77d8c671ef36b61e9b14e2", size = 5088747, upload-time = "2026-07-17T10:01:14.42Z" }, + { url = "https://files.pythonhosted.org/packages/92/9c/92a460bac1f6cfd6f96251802b3098a804fb251dfe0b5eb004ede958ae0e/pypdfium2-5.12.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:715ae16b34ea1d64884d58800155179ba700e9ea65a2f583b020666acd2bfb12", size = 5049695, upload-time = "2026-07-17T10:01:15.961Z" }, + { url = "https://files.pythonhosted.org/packages/f7/67/53c61d366222550220b42a9212131407f49d3dbcf050178c620bf80fa899/pypdfium2-5.12.1-py3-none-win32.whl", hash = "sha256:e5358d2ce4ebc5c899aab1df9ca5d215357244e9168aa443225d3c1e649c7eac", size = 3725466, upload-time = "2026-07-17T10:01:17.773Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c3/08b62718faf2f6b6aa49207626e3113ff3ec1b3cd076c0ef8fd852f0e57c/pypdfium2-5.12.1-py3-none-win_amd64.whl", hash = "sha256:9609be73a6701a68f29dffe0335f7a2e4b3ba581542ed65d35d49f761a4600ca", size = 3859845, upload-time = "2026-07-17T10:01:19.417Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d5/ad551e55790134c8bc87ea16e0866a3721def0620fbfa19112c8ad4a25a6/pypdfium2-5.12.1-py3-none-win_arm64.whl", hash = "sha256:afc0b7e0c975a429abc75875209ce17b66d749f6ac5cbe8ba72470e83901e304", size = 3674605, upload-time = "2026-07-17T10:01:21.008Z" }, +] + [[package]] name = "pyreadline3" version = "3.5.6"