Skip to content

Refuse integers that cannot be sent exactly (#963) - #964

Closed
rawsun007 wants to merge 5 commits into
erwindon:masterfrom
rawsun007:fix/refuse-inexact-integers
Closed

Refuse integers that cannot be sent exactly (#963)#964
rawsun007 wants to merge 5 commits into
erwindon:masterfrom
rawsun007:fix/refuse-inexact-integers

Conversation

@rawsun007

Copy link
Copy Markdown

Fixes #963, taking the "raise an error" direction you asked for rather than the string coercion I had suggested — your command-line output settles it: salt keeps the value the user typed, so anything SaltGUI rounds is simply a different number, and there is nothing sensible to send.

The integer branch now refuses when the value is not exactly representable, matching the float branch immediately below it that already refuses a value it cannot represent:

12345678901234567   ->  error: Integer argument is too large to be sent exactly
9007199254740991    ->  9007199254740991      (largest exact integer, unchanged)
20180814033130818988 -> "20180814033130818988" (job-id, still a string via getPatJid)

The boundary is 2**53-1, so everything through 9007199254740991 is unaffected. Job-ids are matched as strings before the integer branch, so #41 keeps working.

One thing worth flagging about the tests. The three existing expectations for long integers were written as numeric literals:

assert.equal(args[0], 2018082000341133831);   // the literal is already ...800

The test file rounds that literal exactly as the parser did, so the assertion compared one rounded value against an identically rounded one and could never fail. They now compare against strings and assert the refusal, with the 2**53-1 boundary and a real job-id added on either side. That is why the diff touches assertions that look unrelated to the change.

npm run test:unit — 300 passing. Reverting only ParseCommandLine.js fails one of the new assertions. npm run eslint and npm run stylelint are clean.

AI disclosure per your policy: the code and this description were written by Claude Code (Claude Opus 5) working through my account, recorded in the commit's ai-assisted-by: trailer. I have not reviewed the diff line by line myself yet — say the word if you would rather I did that before you spend time on it.

An integer above 2**53-1 was accepted and rounded on the way to salt, so
`12345678901234567` arrived as `...68`. The command-line keeps the value the
user typed, as you showed on the issue, so the number SaltGUI sends was simply
a different one.

The integer branch now returns an error, matching the float branch beside it
that already refuses a value it cannot represent. Job-ids are unaffected:
getPatJid() matches them as strings before this point.

The three existing expectations for long integers compared against numeric
literals, which the test file rounded identically, so they could not tell a
correct value from a wrong one. They now compare against strings and assert
the refusal, with the 2**53-1 boundary and a real job-id added either side.

ai-assisted-by: Claude Code (Claude Opus 5)
Signed-off-by: Roshan Ramani <roshanramani.dev@gmail.com>
SonarQube flagged 39% duplication on new code: the added cases repeated the
same four-line setup-and-assert block six times. Two loops over a list of
values cover the same inputs in half the lines, and name the value in each
assertion message so a failure still says which one broke.

No change to what is asserted.

ai-assisted-by: Claude Code (Claude Opus 5)
Signed-off-by: Roshan Ramani <roshanramani.dev@gmail.com>
SonarQube read `assert.equal(String(args[0]), nr, nr)` as a likely copy-paste
slip, which is fair: the same variable served as both the expected value and
the failure message. Each loop now builds a label once and uses it for the
messages, leaving the value argument on its own.
@erwindon erwindon self-assigned this Sep 7, 2026
@erwindon
erwindon marked this pull request as draft September 7, 2026 10:37
@erwindon
erwindon force-pushed the fix/refuse-inexact-integers branch 2 times, most recently from 9fb0425 to b3dcf92 Compare September 9, 2026 16:46
@erwindon erwindon assigned rawsun007 and unassigned erwindon Sep 11, 2026
@rawsun007
rawsun007 marked this pull request as ready for review September 12, 2026 03:27
@erwindon

Copy link
Copy Markdown
Owner

@rawsun007
I do not see any changes after my review comments and also no replies to that...
I accidentally committed and pushed a few changes several days ago and quickly fixed that, did that interfere somehow?

@erwindon
erwindon marked this pull request as draft September 13, 2026 10:14
@rawsun007

Copy link
Copy Markdown
Author

nothing reached me, and i think i know why: there are no review comments visible on this pr at all. the reviews endpoint returns an empty list, so does the inline comments one, and the only comments on the thread are sonarcloud's from the 9th and yours from today. if you wrote them in a review you never pressed "submit review" on, they stay private to you until you do.

your pushes did not break anything. the branch is still my three commits (681fdb7, 98f9a81, b3dcf92) and the diff is the safe-integer guard plus the table-driven tests, so whatever went in on the 9th you did undo cleanly.

i also did not mean to fight the draft state. i marked it ready yesterday because the wip check was blocking on "draft mode override" and i read the silence as it being finished; i had not realised you set it to draft deliberately on the 7th. it is back in draft now and i will leave it there.

so: please resend or submit the review and i will get on with it. quality gate is green and the duplication issue from the 7th is fixed.

Assisted-by: Claude Opus 5 (Claude Code).

Comment thread saltgui/static/scripts/ParseCommandLine.js Outdated
// The salt command-line keeps the exact value (as an int, or as a string
// once it is long enough), so refusing is the only honest answer here.
// Job-ids are matched as strings before this point, see getPatJid().
return { error: "Integer argument is too large to be sent exactly" };

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Can we suggest a way forward also?
e.g.
Integer argument is too large to be sent exactly. Make it a string by surrounding it with quotes or make it a float by appending .0

@erwindon

erwindon commented Sep 13, 2026

Copy link
Copy Markdown
Owner

my bad... I did not click on "submit review" after making notes.
and don't worry about the draft state. I often put it on (or back) so that I do not accidentally merge.

isSafeInteger refuses everything above 2**53-1, but the value is sent as
its own decimal rendering, so what matters is whether that rendering is
the text that was typed. 2**53, 2**54 and 10**16 all survive; they were
being refused.

Comparing the rendering against the input accepts those and still refuses
12345678901234567, which comes back as ...68.

The error now names the two ways out, as suggested in review.
@rawsun007

Copy link
Copy Markdown
Author

you were right about isSafeInteger, thanks. pushed ecbc965.

what actually matters here is not whether the double is exact but whether the number is sent as the same text that was typed, because it goes out as its own decimal rendering. that is a wider range than isSafeInteger allows:

9007199254740991   -> 9007199254740991     accepted before and now
9007199254740992   -> 9007199254740992     refused before, accepted now
18014398509481984  -> 18014398509481984    refused before, accepted now
10000000000000000  -> 10000000000000000    refused before, accepted now
12345678901234567  -> 12345678901234568    refused, still refused
2018082000341133831 -> 2018082000341133800 refused, still refused

so the check is now String(value) !== pStr rather than !Number.isSafeInteger(value).

on your third note, testing whether the value is still an integer does not separate these: Number.isInteger(20987094501194539841) is true, because the rounded result is still integral. the rendering comparison is what catches it.

one case worth knowing, since it is not intuitive: 2**60 is exactly representable as a double, but javascript renders it as 1152921504606847000, so it is still refused. that is correct, salt would receive the rendered number rather than the one typed.

error message now uses your wording: "Integer argument is too large to be sent exactly. Make it a string by surrounding it with quotes or make it a float by appending .0"

your hex example needs #966 first, since patInteger does not match 0x… at all yet; it falls through and is sent as a string today.

300 unit tests pass; reverting just the source leaves 1 failing. eslint clean.

Assisted-by: Claude Opus 5 (Claude Code).

Comment thread saltgui/static/scripts/ParseCommandLine.js Outdated
Assisted-by: Claude Opus 5 (Claude Code)
@sonarqubecloud

Copy link
Copy Markdown

@erwindon

Copy link
Copy Markdown
Owner

observation: I thought that e.g. "011" was treated as a octal-integer in SaltGUI. in reality, it is not recognized as an integer (it does not match our pre-check regexp). it is then parsed as a float (Number.parseFloat) which actually returns an integer!

The solution in this PR conflicts with the goals that I have since registered in #966. For that issue I now have a vision which handles all the formats described there and warns for it while you type.

This means that I will not merge this PR. But your issue was certainly the starting point of all that and will be credited!

@erwindon erwindon closed this Sep 14, 2026
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.

Long integers other than job-ids are still silently rounded (residue of #40)

2 participants