Refuses a duration component past the safe range - #156
Merged
Merged
Conversation
A duration text whose component, as read, is not a safe integer is no longer a duration here: readDuration answers nothing, so the duration cast answers undefined and parseDuration answers invalid_duration_format, where both answered a duration whose component was infinite or rounded. The reference, whose integers have no bound, answers such a text with a duration, and the parseDuration doc comment now names that exception. ADR-0002 gains an Amendment at proposed declaring the difference (ruled by the operator, 2026-10-01). durationToMilliseconds answers NaN for a component that is not a number, rather than throwing on a bigint or a symbol, and the test comment on its unbounded sum names who decided it. Refs: pts-o0gr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes
A duration text whose component, as read, is past the largest safe integer is refused (ruled by the operator, 2026-10-01):
parseDurationanswers its failing arm with the existing reasoninvalid_duration_format. No reason token is added.durationtarget of the cast answers undefined, as it does for every text it cannot read. That is the cast exemption already accepted in ADR-0002, the Amendment headed "the out-of-range rule's sites, and the cast exemption", which makes a cast total and says a string-to-duration parse past the bound is covered by it.Before this, such a text read as a duration whose component was infinite (a count too long for a double) or rounded (a count a double cannot hold exactly), which the tagged encoder could not write. The check is in
readDuration(src/cast.ts) and runs on each component after the parse has added it up, so it covers a component written too long, a repeated unit that sums past the bound, and the whole part of a fraction. A count with leading zeros is judged by its value.The reference reads integers of any size. Run in a detached export of predicator-ex
v9.4.2(Elixir 1.18.3, OTP 27), it answers each of the six refused texts in the tests with a duration. ADR-0002 declares the difference.Also in this change:
durationToMillisecondsanswersNaNfor a component that is not a number, where a bigint or a symbol component used to throw. Its "never throws" promise in the doc comment and the README now holds for an untyped caller.parseDurationdoc comment now names the one exception to "answers what the reference's own duration parse answers".durationToMilliseconds's sum past the safe range now says the plain-number answer was decided under the night rule by the conductor, 2026-10-01.The record
ADR-0002 gains, at its foot, "Amendment: a duration component past the safe integer range is refused when a text is read (2026-10-01)" at
Status: proposed. It is an Amendment rather than a Note becausedocs/adr/README.mdsays an amendment changes what a record decides and a note does not, and this change alters an answer. It has its own heading rather than sitting under the preceding Note's "What this note does not decide", because that Note changes no answer.git diff origin/main...HEAD -- docs/adr/shows no removed line.Changelog
changelog.d/pts-o0gr.md, under### Changed. No fragment for thedurationToMillisecondsguard: that export has not been released yet.Tests
test/cast.test.ts: "refuses a component past the largest safe integer"; "reads a component at the largest safe integer, and one written with leading zeros".test/parse-duration.test.ts: the describe block "parseDuration past the largest safe integer", which asks both the export and the cast for each refused text, and reads one component at the bound.test/duration-to-milliseconds.test.ts: "answers NaN rather than throwing for a component that is not a number".Sabotage, each run against the three test files and restored byte-equal:
The full gate is green on this head.
Provenance
src/index.tsedit is only theparseDurationdoc comment. The conductor's file map left it out at first and later authorized it. A sibling change edits only the export list in that file.README.mdis untouched.Refs: pts-o0gr