diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 42b53b06ad..598dbd1bd4 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -1169,6 +1169,9 @@ This file is append-only. Never rewrite or delete an existing review record; app | 2026-07-27 | PR #1280 / `claude/top-search-design-mockups-w53znc` | `980b4298` | Implemented review follow-up | Synced main; rail overflow observes childList mutations. Temporarily disabled auto-merge to land polish without squash race. | Focused band Vitest 9/9; no provider checks. | | 2026-07-27 | PR #1281 / `claude/safety-planning-tools-page-tsq4vs` | `f7e616d1` | Implemented review polish | StepBuilderCard filled uses `isStepComplete`; clipboard DRAFT assertion added. Auto-merge temporarily disabled to land polish. | Focused safety-plan Vitest 3/3; no provider checks. | | 2026-07-27 | PR #1261/#1262/#1263 audit cluster | closed tips | Close without merge | Closed per review: unsafe lineage / tip markers / privacy+RAG P1s / parallel verify:cheap rewrite. Thin PDF exit-137 salvage opened separately. | Prior Bugbot + merge-tree evidence; no provider checks. | +| 2026-07-27 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | pending-push | CI babysit + Bugbot + main sync | Before: required CI SUCCESS on tip `630792c9`; mergeable but BEHIND main; 0 unresolved review threads; no `cursor[bot]` Bugbot comments. After: merged `origin/main` cleanly; pr-bugbot found no P0/P1 — fixed P2 by moving SIGKILL/exit-137 regressions out of `describe.runIf(hasPyMuPDF)` and asserting `PdfExtractorProcessError` by name so the OOM path cannot silently skip or pass via JS fallback. | Focused Vitest `tests/pdf-extractor.test.ts` 2 passed / 4 skipped (PyMuPDF absent locally); merge-tree clean; no provider-backed checks. | +| 2026-07-27 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `dd9d96b64042004f9162b5ef2eaf4495073a5a60` | CI babysit + Bugbot + main sync (exact head) | Supersedes pending-push row. Merged origin/main; no failing required CI on prior tip; 0 review threads; no hosted cursor[bot] comments. Fixed P2: process-failure tests ungated from hasPyMuPDF and assert PdfExtractorProcessError by name. No P0/P1. | Vitest tests/pdf-extractor.test.ts 2 passed / 4 skipped; merge-tree clean; no provider checks. | +| 2026-07-27 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `bfd66ba8546b215e4d98ec46fcdd2a8538d053a0` | CI babysit + Bugbot closeout | Final pushed tip after main sync + process-failure test ungate. Required CI re-running on this head. | Local Vitest process-failure 2/2; prior tip required CI SUCCESS; no provider checks. | | 2026-07-27 | PR #1287 / `claude/site-audit-quick-wins-21v9gb` | `88d8638974075fa91334c2bb4a0e6b54fda00176` | Review closeout: main sync + resolved-graph guard + ledger attribution | FIXED. Cause of GitHub CONFLICTING/DIRTY: both tips appended `docs/branch-review-ledger.md` (union); `git merge-tree` was clean — merged `origin/main` (#1284 ledger rows). CodeRabbit recursive import-graph ask: walk resolved runtime imports from `cross-mode-differentials.ts` (services/forms boundary pattern) + keep entry allowlist. Supersedes residual wording on rows 1148/1149: import-graph lock + scripts-index + comment already landed; `client-performance-boundaries` guards the consumer dynamic import, `cross-mode-differentials-index` guards the catalog module/graph. Hosted Production UI already green after hydration settle. | Focused vitest index+boundaries 10/10; `check:cross-mode-index` PASS; merge-tree CLEAN vs origin/main; prior Production UI PASS on `f738f083`; no provider-backed checks. | | 2026-07-27 | PR #1287 / `claude/site-audit-quick-wins-21v9gb` | `662a93f826ea6ba34df9d15677ef5ae2446a2e40` | Static PR Format check fix | FIXED. Hosted `static-pr` Format check failed on Prettier for `tests/cross-mode-differentials-index.test.ts` after the resolved-graph guard. Reformatted; no behaviour change. Mergeable vs main (merge-tree CLEAN, 0 behind). Prior review threads already dispositioned. | `prettier --check` local PASS for the file; vitest index test 3/3; no provider-backed checks. | | 2026-07-28 | PR #1292 / `codex/chat-clinical-grounding-cap-bbc4` | `2e5ee9f891d9f251adffb6a15bc2ab13e0f18b23` | CI babysit + Bugbot | Blocking PR policy fixed via temporary `PR_POLICY_BODY.md` sync (Clinical Governance Preflight all checked, Risk/Verification completed), then template removed. Merge with main clean. Bugbot: zero `cursor[bot]` findings; offline scan of unique claim-cap fail-closed diff found no high-confidence defect. No review threads. Residual: human approving review once exact-head required checks finish. | Local: `npx vitest run tests/rag-claim-support.test.ts` 40/40; `evaluatePullRequestPolicy` ok. Hosted prior tip `19495e7c`: PR policy + Sync SUCCESS. No OpenAI/live Supabase. | @@ -1195,9 +1198,14 @@ This file is append-only. Never rewrite or delete an existing review record; app | 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `f4b55751` | CodeRabbit behavioral prefetch-test disposition | RESOLVED. Behavioral DOM coverage for menu-open prefetch paths (later adapted to per-option model). | focused vitest PASS; no provider checks. | | 2026-07-27 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `81005d18` | Codex mojibake-ledger disposition | RESOLVED. Historical rows restored byte-for-byte from origin/main; append-only thereafter. | exact prefix check; check:branch-review-ledger PASS; no provider checks. | | 2026-07-28 | PR #1275 / `codex/identify-and-fix-performance-issues-during-mode-switch` | `01469840` | CI/merge conflict closeout + Bugbot triage | RESOLVED merge conflict with origin/main (7ae4eb49 per-option prefetchModeHome). Dropped superseded bulk prefetchModeHomes; menu-open warms only highlighted option; focus/pointer scanning retained. CodeRabbit duplicate/malformed ledger threads dispositioned (main-owned). No open cursor[bot] Bugbot product defects. | merge-tree clean; focused vitest 12/12; ledger restored from main + appends; no provider checks. | +| 2026-07-28 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `f1e422e8ee64f7e161e78d9a56707a1a83cc3374` | CI babysit: PR policy + main sync | Before: PR marked ready → PR policy FAIL (missing Clinical Governance Preflight); GitHub CONFLICTING/DIRTY but merge-tree clean (17 behind). 0 unresolved review threads; Bugbot no P0/P1. After: merged origin/main; PR body updated with complete Clinical Governance Preflight (7/7 checked). | Local pr-policy evaluate ok; Vitest process-failure 2/2; no provider checks. | +| 2026-07-28 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `734931960175afa12359e84c030290396c381bb5` | CI babysit closeout | Final tip after main sync + Clinical Governance Preflight body fix for ready PR. | Awaiting exact-head PR policy/required CI. | +| 2026-07-28 | PR #1292 / `codex/chat-clinical-grounding-cap-bbc4` | ff40a2b945caf657b45cec0d662317057c63abe3 | CI babysit + main sync + Bugbot | GitHub DIRTY/CONFLICTING with clean `merge-tree` (2 behind main). Merged `origin/main` with no content conflicts. CI already green on prior tip; no product test failures. Bugbot: reviewThreads=0; product fail-closed scan clean. No comments to resolve. | Local overflow Vitest 1/1; ledger guard pass; awaiting exact-head hosted CI. No providers. | +| 2026-07-28 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `0cab0a6475a9744e7d64a25dedb4a89b06909464` | CI babysit re-sync | Re-merged origin/main after GitHub DIRTY/staleness (merge-tree clean). PR policy already SUCCESS with Clinical Governance Preflight. 0 review threads. | merge-tree clean; hosted PR policy/required were SUCCESS on prior tip; no provider checks. | | 2026-07-28 | PR #1287 / `claude/site-audit-quick-wins-21v9gb` | `562bce2b3c90bf1790da9683077915cd3f8fdb17` | Main sync + conflict repair + Bugbot closeout | FIXED. Real CONFLICTING vs advanced main was `docs/outstanding-issues.md` only (ledger/ui-smoke auto-merged). Resolution keeps `#012` in Resolved with this PR's outcome while retaining main's newer open/archive rows. CI on prior tip was fully green (Static/Production UI/PR required); re-runs after sync. Review threads already dispositioned (resolved-graph guard, ledger residuals, attribution). | merge-tree CLEAN; focused vitest index+boundaries 10/10; `check:cross-mode-index` PASS; `prettier --check` on touched tests PASS; Bugbot pass pending agent; no provider-backed checks. | | 2026-07-28 | PR #1287 / `claude/site-audit-quick-wins-21v9gb` | `742b0d154f7058800c945b3ec6e720eef24ce4c0` | Bugbot P2: finish #012 recommended-queue closeout | FIXED. After main-sync conflict repair, `#012` was correctly Resolved/Open-clean but the Recommended execution queue still listed it (order 20 composite + #017 Before hint). Applied `/issues done` queue rewrite: order 20 is now `#013`, `#016`; #017 timing is Before `#013`/`#016`. | Bugbot review on `1b31607b`; queue/Open/Resolved audit; focused vitest previously green; no provider-backed checks. | -| 2026-07-28 | PR #1292 / `codex/chat-clinical-grounding-cap-bbc4` | ff40a2b945caf657b45cec0d662317057c63abe3 | CI babysit + main sync + Bugbot | GitHub DIRTY/CONFLICTING with clean `merge-tree` (2 behind main). Merged `origin/main` with no content conflicts. CI already green on prior tip; no product test failures. Bugbot: reviewThreads=0; product fail-closed scan clean. No comments to resolve. | Local overflow Vitest 1/1; ledger guard pass; awaiting exact-head hosted CI. No providers. | | 2026-07-28 | PR #1287 / `claude/site-audit-quick-wins-21v9gb` | `b90d659be12efedd339297daa2d289c2bd7ebb03` | Sync main + Format check on outstanding-issues | FIXED. Cause of GitHub CONFLICTING/DIRTY: branch 1 behind main (`11a4ed74` numeric claim truncation); `git merge-tree` CLEAN — ledger union auto-merge. Cause of Static PR red: Prettier on `docs/outstanding-issues.md` after queue closeout rewrite. Merged main; reformatted file; `#012` remains Resolved and out of the recommended queue. | merge-tree CLEAN; `prettier --check` PASS; `check:branch-review-ledger` PASS; no provider-backed checks. | +| 2026-07-28 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `c5ee34f2a17222a0ec6fb592a2dd7db4e43f1496` | CI babysit + Bugbot recheck | Before: required CI SUCCESS; GitHub CONFLICTING/DIRTY from 1-commit main staleness (merge-tree clean); 0 review threads. Bugbot: no P0/P1/product P2. After: merged origin/main (#1287). Nothing to resolve for comments. | Prior tip required CI SUCCESS; merge-tree clean; no provider checks. | +| 2026-07-28 | PR #1285 / `cursor/pdf-extractor-sigkill-137-0687` | `1c77291a93373b56c136075b5941f5e61ac2859b` | Ledger hygiene after main merge | Dropped one exact-duplicate #1292 babysit row introduced by ledger `merge=union` during main sync; first copy retained; zero unique records lost. | `check:branch-review-ledger` PASS after dedupe; no provider checks. | | 2026-07-28 | PR #1291 / `claude/issues-upload-limit-sync-123366` | `1607558188283d3497683f1067835d96f1031d3c` | CI babysit + merge conflict + Bugbot | FIXED. GitHub CONFLICTING/DIRTY was a real content conflict in `docs/outstanding-issues.md`: main had claimed `#084` for completed per-result grading evidence, colliding with this PR's upload-limit capture. Resolved by keeping main's ledger, renumbering the upload-limit recommendation to `#085`, and bumping `issues:next-id` to `086`. Synced again when main advanced with #1300. CodeRabbit date thread already resolved. Bugbot: zero `cursor[bot]` findings. Required CI green (PR required SUCCESS). | merge-tree CLEAN; prettier + docs:check-links PASS; hosted Change scope/Static/PR required SUCCESS; no provider-backed checks. | | 2026-07-28 | PR #1291 / `claude/issues-upload-limit-sync-123366` | `af140d11d5ca23dee0d8705d9933db967fc8c404` | Babysit closeout tip | Supersedes prior #1291 row at `16075581` after appending the conflict/Bugbot ledger record. Product delta vs main unchanged: `#085` upload-limit capture only. merge-tree CLEAN; awaiting exact-head required checks. | ledger append + check:branch-review-ledger PASS; prior tip hosted PR required SUCCESS. | diff --git a/src/lib/extractors/document.ts b/src/lib/extractors/document.ts index 9bbd2644c9..504e164cac 100644 --- a/src/lib/extractors/document.ts +++ b/src/lib/extractors/document.ts @@ -210,9 +210,11 @@ export async function runPythonPdfExtractor( ); return; } - if (signal) { + if (signal || code === 137) { finish(() => - reject(new PdfExtractorProcessError(stderr || `PDF extractor exited with code ${code} (${signal})`)), + reject( + new PdfExtractorProcessError(stderr || `PDF extractor exited with code ${code} (${signal || "SIGKILL"})`), + ), ); return; } diff --git a/tests/pdf-extractor.test.ts b/tests/pdf-extractor.test.ts index 8eeb723848..2bb34db008 100644 --- a/tests/pdf-extractor.test.ts +++ b/tests/pdf-extractor.test.ts @@ -202,7 +202,9 @@ describe.runIf(hasPyMuPDF)("Python PDF table extraction", () => { }); }); -describe.runIf(hasPyMuPDF)("Python extractor fallback", () => { +// Process-death paths use scriptPathOverride only — they must not depend on PyMuPDF +// being installed, or the SIGKILL/137 regressions can silently skip outside CI. +describe("Python extractor process failures", () => { it.skipIf(process.platform === "win32")("rejects cleanly if the python process dies with SIGKILL", async () => { const root = await mkdtemp(path.join(tmpdir(), "clinical-kb-extractor-test-")); try { @@ -217,9 +219,33 @@ describe.runIf(hasPyMuPDF)("Python extractor fallback", () => { const pdfBuffer = await readFile(pdfPath); - await expect(extractPdf(pdfBuffer, { scriptPathOverride: scriptPath })).rejects.toThrow( - /PDF extractor exited with code/, - ); + await expect(extractPdf(pdfBuffer, { scriptPathOverride: scriptPath })).rejects.toMatchObject({ + name: "PdfExtractorProcessError", + message: expect.stringMatching(/PDF extractor exited with code/), + }); + } finally { + await rm(root, { recursive: true, force: true }); + } + }); + + it.skipIf(process.platform === "win32")("rejects cleanly when the python process exits with code 137", async () => { + const root = await mkdtemp(path.join(tmpdir(), "clinical-kb-extractor-test-")); + try { + const pdfPath = path.join(root, "table.pdf"); + const scriptPath = path.join(root, "exit_137.py"); + + await mkdir(root, { recursive: true }); + await writeSyntheticTablePdf(pdfPath); + + // OOM killer often surfaces as exit code 137 with no Node signal. + await writeFile(scriptPath, "import sys\nsys.exit(137)\n"); + + const pdfBuffer = await readFile(pdfPath); + + await expect(extractPdf(pdfBuffer, { scriptPathOverride: scriptPath })).rejects.toMatchObject({ + name: "PdfExtractorProcessError", + message: expect.stringMatching(/PDF extractor exited with code 137 \(SIGKILL\)/), + }); } finally { await rm(root, { recursive: true, force: true }); }