Skip to content

fix: reject fractional PDF page selections#99403

Closed
ZengWen-DT wants to merge 1 commit into
openclaw:mainfrom
ZengWen-DT:fix/99393-reject-fractional-pdf-pages
Closed

fix: reject fractional PDF page selections#99403
ZengWen-DT wants to merge 1 commit into
openclaw:mainfrom
ZengWen-DT:fix/99393-reject-fractional-pdf-pages

Conversation

@ZengWen-DT

Copy link
Copy Markdown
Contributor

Closes #99393

What Problem This Solves

Fixes an issue where users could pass fractional PDF page filters such as pages: "1.5" and have the value accepted by the PDF tool parser. In extraction fallback mode, that non-integer page selection could later be filtered out before extraction, which made the request continue without the page content the user asked for instead of returning a clear input error.

Authoring: AI-assisted.

Why This Change Was Made

The PDF page parser now rejects single-page tokens unless they use integer page syntax, matching the documented 1-based page-number contract and the existing integer-only range parser. The fix stays at the shared parser boundary so invalid input is rejected before native-provider checks or extraction fallback receive page numbers.

User Impact

Users now get an actionable Invalid page number: "1.5" error for fractional PDF page filters instead of a potentially misleading PDF analysis result based on no selected extracted pages.

Evidence

Before the change, the parser accepted fractional single-page tokens on current main:

node --import tsx -e 'import { parsePageRange } from "./src/agents/tools/pdf-tool.helpers.ts"; console.log(JSON.stringify(parsePageRange("1.5", 20))); console.log(JSON.stringify(parsePageRange("1,1.5", 20)));'
[1.5]
[1,1.5]

After the change, the same parser inputs fail at the public input boundary:

1.5 Invalid page number: "1.5"
1,1.5 Invalid page number: "1.5"

Real PDF tool execution with pdfModel.primary = "deepseek/deepseek-v4-pro" and a local PDF fixture now rejects the fractional page selection before model analysis:

Invalid page number: "1.5"

Focused validation:

node scripts/run-vitest.mjs src/agents/tools/pdf-tool.helpers.test.ts
[test] passed 1 Vitest shard ... Tests 24 passed

node scripts/run-vitest.mjs src/agents/tools/pdf-tool.test.ts
[test] passed 1 Vitest shard ... Tests 27 passed

oxfmt --check --threads=1 src/agents/tools/pdf-tool.helpers.ts src/agents/tools/pdf-tool.helpers.test.ts src/agents/tools/pdf-tool.test.ts
All matched files use the correct format.

tsgo -p tsconfig.core.json --noEmit --declaration false --singleThreaded --checkers 1
passed

tsgo -p test/tsconfig/tsconfig.test.src.json --noEmit --declaration false --singleThreaded --checkers 1
passed

git diff --check
passed

Build/runtime smoke:

node scripts/run-node.mjs --version
OpenClaw 2026.6.11

Live DeepSeek agent lane:

node scripts/run-node.mjs qa manual --provider-mode live-frontier --model deepseek/deepseek-v4-pro --alt-model deepseek/deepseek-v4-pro ...
status: ok
model: deepseek/deepseek-v4-pro

The QA manual tool inventory did not expose pdf, so the PDF-specific behavior proof above uses the actual createPdfTool execution path rather than the QA manual agent surface.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS labels Jul 3, 2026
@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 3:01 AM ET / 07:01 UTC.

Summary
The branch tightens parsePageRange to reject non-integer single-page tokens and adds helper plus PDF tool regression tests for fractional pages input.

PR surface: Source +3, Tests +28. Total +31 across 3 files.

Reproducibility: yes. Current main clearly parses "1.5" through Number(part) in parsePageRange, and fallback extraction then filters non-integer page numbers with Number.isInteger.

Review metrics: 1 noteworthy metric.

  • Tool Argument Validation: 1 public tool argument tightened. The PDF tool pages input now rejects fractional single-page tokens before provider or extractor execution, which is a small but intentional input-contract change.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #99393
Summary: The canonical issue is the fractional PDF page-token parser bug; this PR and #99399 are competing open fix candidates for that same root cause.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

Risk before merge

  • [P1] This intentionally turns undocumented fractional pages values into clear input errors, so anyone relying on the current permissive parsing will need to send integer page selections.
  • [P1] A parallel open PR, fix(pdf): reject fractional page selections #99399, changes the same parser boundary; maintainers should not land both as separate fixes.

Maintainer options:

  1. Accept Integer-Only Pages (recommended)
    Land one of the parser-boundary fixes because the docs and existing range syntax define integer page selection, then close the duplicate open fix candidate.
  2. Pause For Compatibility Policy
    Pause both fractional-page PRs only if maintainers want fractional tokens to remain accepted and define a product contract for how extraction should map them.

Next step before merge

  • No automated repair is needed; a maintainer should choose this PR or the sibling PR as the single fix to land for the linked issue.

Security
Cleared: The diff only tightens PDF parser validation and adds tests; it does not touch dependencies, workflows, secrets, package metadata, or code execution supply-chain surfaces.

Review details

Best possible solution:

Land one parser-boundary integer-validation fix with helper and tool-boundary regression coverage, then close the linked issue and the unmerged sibling PR.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main clearly parses "1.5" through Number(part) in parsePageRange, and fallback extraction then filters non-integer page numbers with Number.isInteger.

Is this the best way to solve the issue?

Yes. Rejecting fractional tokens in parsePageRange is the best layer because that helper is the shared conversion boundary before both native-provider checks and extraction fallback.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against e878efe9508e.

Label changes

Label justifications:

  • P2: This fixes a normal-priority PDF tool input bug with misleading-output risk but narrow blast radius.
  • merge-risk: 🚨 compatibility: The PR deliberately changes previously accepted fractional pages input into a hard validation error for existing users who pass that form.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal evidence from parser probes and a real createPdfTool execution path rejecting fractional page input before model analysis.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal evidence from parser probes and a real createPdfTool execution path rejecting fractional page input before model analysis.
Evidence reviewed

PR surface:

Source +3, Tests +28. Total +31 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 1 3 0 +3
Tests 2 28 0 +28
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 31 0 +31

What I checked:

  • Current main accepts fractional page tokens: On current main, parsePageRange documents 1-based page numbers but still parses single tokens with Number(part) before only checking finiteness and lower bound, so "1.5" remains accepted before this PR. (src/agents/tools/pdf-tool.helpers.ts:49, e878efe9508e)
  • Caller forwards parsed pages to both execution paths: The PDF tool computes pageNumbers from parsePageRange and passes them to extraction and model routing, making the helper the shared input boundary. (src/agents/tools/pdf-tool.ts:498, e878efe9508e)
  • Fallback extraction drops non-integer pages: The document extractor filters requested pages through Number.isInteger(p), so a fractional parsed page can be silently removed downstream instead of rejected at input parsing. (extensions/document-extract/document-extractor.ts:68, e878efe9508e)
  • Documented contract is integer-style page selection: The public PDF docs describe pages as examples like 1-5 or 1,3,7-9 and say it is parsed as 1-based page numbers, matching integer-only validation. Public docs: docs/tools/pdf.md. (docs/tools/pdf.md:52, e878efe9508e)
  • PR diff fixes the parser boundary and adds coverage: The PR adds a digit-only check before single-page numeric conversion and adds helper plus PDF tool tests that reject pages: "1.5" before native analysis. (src/agents/tools/pdf-tool.helpers.ts:65, 80d5d6af344d)
  • Real behavior proof and CI evidence are present: The PR body includes before/after parser output, copied real PDF tool execution output showing Invalid page number: "1.5", focused Vitest, oxfmt, tsgo, diff-check, and a live DeepSeek lane; live PR checks reported clean mergeability and successful relevant CI/security checks. (80d5d6af344d)

Likely related people:

  • tyler6204: Authored and merged the original PDF analysis tool PR that added parsePageRange, the pages parameter, and the main PDF tool implementation. (role: introduced behavior; confidence: high; commits: 2c257cf97d13, 0b57ca3b5ce3, d0ac1b019517; files: src/agents/tools/pdf-tool.helpers.ts, src/agents/tools/pdf-tool.ts, src/agents/tools/pdf-tool.test.ts)
  • zhangguiping-xydt: Authored the recent neighboring fix that tightened empty parsed page ranges in the same helper and tests. (role: recent adjacent repair author; confidence: high; commits: a5165d6a8486, aadd57c31cc8; files: src/agents/tools/pdf-tool.helpers.ts, src/agents/tools/pdf-tool.helpers.test.ts, src/agents/tools/pdf-tool.test.ts)
  • steipete: Git history shows multiple PDF tool helper/test refactors around this parser and test surface. (role: recent area contributor; confidence: medium; commits: 7240830ca42f, 42ae213ba6f4, 998cc02af40c; files: src/agents/tools/pdf-tool.helpers.ts, src/agents/tools/pdf-tool.helpers.test.ts, src/agents/tools/pdf-tool.test.ts)
  • vincentkoc: Merged the adjacent empty-page parser fix and has recent history touching shared PDF test setup in the affected area. (role: recent merger and adjacent contributor; confidence: medium; commits: aadd57c31cc8, b4f5c748c3da; files: src/agents/tools/pdf-tool.helpers.ts, src/agents/tools/pdf-tool.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 3, 2026
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

The canonical fix has landed in #99399 as ae4a1e236f7e.

That version enforces positive-integer tokens in the shared page-range parser, validates before media/model work, and includes both parser and real tool-boundary regression coverage. Exact-head CI passed; focused sanitized-AWS proof passed 51/51 assertions plus a nonexistent-file smoke proving fractional input fails before I/O.

Closing this duplicate. Thank you @ZengWen-DT for independently identifying and testing the same bug.

@steipete steipete closed this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: PDF tool accepts fractional page numbers that select no extracted pages

2 participants