Skip to content

Paths: anchor and drawing commands refuse a number given as text - #3266

Open
dotCooCoo wants to merge 1 commit into
storytold:mainfrom
dotCooCoo:fix/anchor-commands-refuse-numbers-as-text
Open

dotCooCoo wants to merge 1 commit into
storytold:mainfrom
dotCooCoo:fix/anchor-commands-refuse-numbers-as-text

Conversation

@dotCooCoo

@dotCooCoo dotCooCoo commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

What and why

On main, the path editing and drawing commands read their optional numbers with f64_or or as_f64, which fall back to a default for a value that is not a JSON number. path.reshapeSegment {"dy": "10"} bends the segment by 0 and reports success, path.convertAnchor {"to": "smooth", "x": "200", "y": "150"} converts the anchor without a handle position, and path.freehand {"redraw": {"within": "4"}} redraws within 12 pt.

  • path.reshapeSegment and object.blend.spine.reshapeSegment (t, dx, dy), path.curvatureEdit (x, y, t), path.convertAnchor (x, y), path.insertAnchor (t), path.freehand (fidelity and the within of redraw), path.eraseRegion and path.blob (size), path.eraseSegments (width), path.smoothRegion (radius, fidelity), path.joinScrub (tolerance), path.moveAnchors (dx, dy) and path.reshape (dx, dy, tol, radius) fail with "<key> must be a number, not " for a value that is not a number or null, as the transform, blend and Object menu commands do since Transform commands: a string for an optional number is an error (#1952) #1967, Blends, meshes and envelopes: a number given as text is refused #2851 and Transform Each, Rasterize, Mosaic, Trim Marks and Rearrange: a number given as text is refused #2917 (check_numbers, crates/engine/src/cmd/mod.rs:323). The document and the undo history stay as they were.
  • path.convertAnchor refuses an x without a y, or a y without an x, with "x and y must be given together", the message object.blend.spine.convertAnchor gives. Before, it converted the anchor without a handle position.
  • path.freehand, path.curvature, path.knife, path.eraseRegion, path.eraseSegments, path.smoothRegion, path.joinScrub and path.blob refuse a point whose x or y is not a number with "x and y must both be numbers", and all of them except path.curvature refuse a pen pressure that is neither a number nor null with "pressure must be a number, not ". Before, they left such a point out, and path.freehand drew a point with such a pressure at full pressure.
  • path.close refuses an in that is not an array of exactly two numbers with "in must be [x, y]". Before, it closed the path without the handle, or used the first two numbers of a longer array.
  • docs/mcp.md lists the keys, and docs/target-app-parity.md has one line for the change. The 19 catalogs that translate every status and error message, and bg, already have rows for "{key} must be a number, not {v}", "x and y must both be numbers" and "{k} must be [x, y]"; the change adds no catalog rows. "x and y must be given together" has no rows there, as for object.blend.spine.convertAnchor.

How it was tested

New tests in vectorcraft-engine, each failing on main, where the first call succeeds:

  • tests_draw2::reshape_segment_refuses_a_number_given_as_text gives t, dx and dy as a string, an array or true; the path stays as it was, and dy: 20 with t: null still bends it.
  • tests_blendspine::spine_reshape_segment_refuses_a_number_given_as_text does the same for a blend's spine.
  • tests_draw2::convert_anchor_refuses_a_handle_position_given_as_text_or_alone gives x and y as text and each one alone; x: 330, y: 150 still places the out handle there.
  • tests_draw2::curvature_edit_and_insert_anchor_refuse_a_number_given_as_text gives the Curvature insert and move edits a t, x or y as text, and path.insertAnchor a t as text.
  • tests_draw2::pencil_refuses_a_fidelity_or_within_given_as_text: no path is drawn or redrawn, and null fidelity and within redraw the line.
  • tests_draw2::drawing_commands_refuse_a_point_or_pressure_given_as_text gives the eight point commands a point with a string x or y, a point written as a string, a point of one number and null, and gives the seven that take a pressure one as text.
  • tests_draw2::drawing_commands_refuse_a_size_given_as_text gives each size, width, radius, fidelity and tolerance as text; a null size erases with the default 10 pt.
  • tests_draw2::move_anchors_reshape_and_close_refuse_a_number_given_as_text gives path.moveAnchors and path.reshape their numbers as text, and path.close four in values that are not [x, y].

Targeted checks while building: cargo clippy -p vectorcraft-engine --all-targets -- -D warnings; the new tests; cargo test -p vectorcraft-engine --lib and --test command_sweep; cargo fmt --all -- --check; cargo xtask brands, layers and assets.

On Windows 11 (x86-64) with rustc 1.99.1, on top of main at bc1ae08:

  • CRAFT_FONTS_DIR=<craft-fonts checkout> cargo xtask ci passes its 10 steps: 8,578 tests passed, 0 failed, 13 ignored.

git merge-tree reports no conflicts with main at bc1ae08, or with #2910, which also changes path.freehand. #2592, #613, #2539 and #2071 also change draw2.rs, path.rs or live.rs, and #613, #1868 and #3053 change tests_draw2.rs; their conflicts with main are the same with or without this branch. cargo check -p vectorcraft-engine --tests passes on the branch merged with #2910.

Checklist

  • cargo xtask ci passes (fmt, clippy, tests, assets, brands, layers, wasm).
  • No panics in shipped code: no unwrap(), expect(), panic!, unreachable!, todo! or
    unimplemented! outside tests, and no unchecked indexing on data from files, parameters or
    messages. Errors are returned as Result and shown to the user
    (why and how).
  • Clean-room: nothing copied from Adobe products or GPL/AGPL code (AGENTS.md).
  • Every new asset has a row in ASSETS.md.

Summary by CodeRabbit

  • Bug Fixes

    • Drawing and path-editing commands now reject malformed, incomplete, non-numeric, or non-finite coordinates and parameters.
    • Invalid input no longer changes the document or records undo history.
    • Handle coordinates must be supplied as complete numeric pairs, and pressure accepts only numeric values or null.
    • null continues to use defaults or omit optional values.
  • Documentation

    • Updated command documentation to describe validation rules and resulting errors.

The path editing and drawing commands read their optional numbers with
f64_or or as_f64, which fall back to a default for a value that is not
a JSON number. path.reshapeSegment {"dy": "10"} bent the segment by 0
and reported success, and object.blend.spine.reshapeSegment did the
same with t, dx and dy. path.convertAnchor converted an anchor without
a handle position when x or y was a string or only one of them was
given. path.curvatureEdit and path.insertAnchor inserted at the middle
of the segment for a t given as text, and path.curvatureEdit left an
inserted anchor where it was when x and y were strings. path.freehand
used 1.5 pt for a fidelity given as text and 12 pt for such a redraw
within. The Eraser, Path Eraser, Smooth, Join and Blob Brush commands
used their default size, width, radius, fidelity or tolerance, and
path.moveAnchors and path.reshape did the same with dx, dy, tol and
radius. The drawing commands left out a point whose x or y was not a
number, path.freehand drew a point at full pressure when its pressure
was text, and path.close closed a path without its handle when in was
not an array starting with two numbers, and used the first two numbers
of a longer array.

These commands now fail with "`<key>` must be a number, not <value>"
for a value that is not a number or null, as the transform, blend and
Object menu commands do. The document does not change and no undo
step is recorded. path.convertAnchor refuses an x without a y, or a y
without an x, with "x and y must be given together", the message
object.blend.spine.convertAnchor gives. A point whose x or y is not a
number is refused with "x and y must both be numbers", and path.close
refuses an in that is not [x, y] with "`in` must be [x, y]".
path.close also refuses an in of more than two numbers.

Docs: docs/mcp.md, docs/target-app-parity.md.
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: storytold/vectorcraft/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5ade7783-43e8-469e-b120-c77bc6ee5bc4
📥 Commits

Reviewing files that changed from the base of the PR and between bc1ae08 and 705601e.

📒 Files selected for processing: 7
  • crates/engine/src/cmd/draw2.rs
  • crates/engine/src/cmd/live.rs
  • crates/engine/src/cmd/path.rs
  • crates/engine/src/tests_blendspine.rs
  • crates/engine/src/tests_draw2.rs
  • docs/mcp.md
  • docs/target-app-parity.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

📝 Walkthrough

Drawing and path-editing commands now reject malformed numeric inputs and coordinates instead of silently ignoring them or applying defaults. Null optional values continue to use defaults or omit optional fields. Regression tests and documentation cover the validation behavior.

Changes: Command Input Validation

Layer / File(s) Summary
Drawing command input validation
crates/engine/src/cmd/draw2.rs, crates/engine/src/tests_draw2.rs
Drawing commands validate points, pressure, and optional numeric parameters before applying defaults or bounds. Tests check rejection without document or undo-history changes.
Path and spine editing validation
crates/engine/src/cmd/draw2.rs, crates/engine/src/cmd/live.rs, crates/engine/src/cmd/path.rs, crates/engine/src/tests_blendspine.rs, crates/engine/src/tests_draw2.rs, docs/mcp.md, docs/target-app-parity.md
Path and spine editing commands validate coordinates and numeric parameters. Tests cover invalid values, null defaults, and valid edits. Documentation describes the checks.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: bflatastic, echelon

Merge Risk: ⚪ Minimal · up to 70560

Numeric pressure continues to be safely clamped, and no outstanding issue prevents merging after normal checks.

Security architecture risk: ⚪ Minimal · up to 70560

The change rejects malformed drawing inputs without adding access or privileges. Validation precedes edits, and existing transaction and preview recovery behavior protects document state. No material security risk introduced or worsened by this change was identified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed input path reaches existing geometry mutations in the active session document, including selected objects, anchors, guides, and blend spines. Comparison with the base shows narrower accepted input, not expanded caller reachability or mutation authority.

Trust Boundaries and Controls

  • observed — Caller-controlled JSON is checked before geometry edits. Existing command enablement, guarded execution, and document transaction checks remain in the execution path; numeric validation does not replace identity or authorization controls.

Resilience and Maintainability Implications

  • observed — Live previews restart from the interaction snapshot rather than accumulating edits. A failed replacement preview clears the pending preview, preventing an earlier successful preview from being committed accidentally; cancellation restores the interaction snapshot.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 5 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: path anchor and drawing commands now reject numeric values provided as text.
Description check Passed The description includes the required What and why, How it was tested, and Checklist sections. It explains the behavior changes, documents regression coverage, reports validation results, and marks al…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description includes the required What and why, How it was tested, and Checklist sections. It explains the behavior changes, documents regression coverage, reports validation results, and marks all checklist items complete.

Full details: Docstring Coverage

Explanation

Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 5 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 LanguageTool
docs/target-app-parity.md

LanguageTool checks are incomplete because the per-file request limit of 5 was reached. Remaining text was skipped; findings from completed checks are retained.

Comment @coderabbitai help to get the list of available commands.

@FredApps FredApps left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 705601e with FreeBSD x86_64 build and test green. The path and drawing commands now refuse a point, pressure, size, width, radius, fidelity, tolerance, t or delta that is not a finite number (naming the key) instead of silently dropping the point or using the default, null still reads as the key left out, path.convertAnchor requires x and y together, path.close validates its in handle, and every refusal leaves the document and undo history untouched; the shared point_entry helper and the per-command check_numbers calls are consistent, and the tests and docs/mcp.md cover each command.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants