Fix v0.1.3 regression: stop coercing stored string values - #8
Merged
Conversation
gillisd
marked this pull request as ready for review
June 22, 2026 16:30
gillisd
force-pushed
the
claude/fervent-hawking-c4docr
branch
2 times, most recently
from
June 22, 2026 16:44
42ea727 to
adfdbb6
Compare
v0.1.3 changed Vivification#vivify_value from a class-based case/when
into a pattern-matching case/in that ran every stored value through
INTEGER/FLOAT/DATELIKE regexes. Because vivify_value runs on every
construction (#initialize -> #vivify) and every assignment (#[]=), this
silently corrupted any string containing a digit:
Flexor.new(address: "123 Main Street").address # => 123
Flexor.new(note: "call me at 3pm").note # => 0.0
Flexor.new(ts: "2023-01-15T10:30:00").ts # => 2023
The branch was also internally broken (the DATELIKE arm does
`require "datetime"`, which does not exist, and calls `it` outside a
block), but INTEGER matched date strings first so that arm was dead.
No spec caught this because every string value in the suite is
digit-free ("alice", "deep", "localhost", ...) and every digit-bearing
datum is either already an Integer or nested inside an Array (which
goes through the untouched vivify_array path).
Restore vivify_value to pass non-Hash/Array values through unchanged,
add regression coverage for construction and assignment of
number-/date-like strings, and remove the stray root-level
patterns_spec.rb left over from the abandoned coercion experiment.
Bump version to 0.1.4
Release the v0.1.3 regression fix (string values were silently coerced
to Integer/Float on every store). 0.1.3 should be considered broken.
Add leading-zero and currency cases to coercion regression specs
Broaden the v0.1.3 regression coverage with two more real-world strings
the coercion destroyed: a leading-zero ZIP ("01970" -> 1970) and a
currency value ("$19.99" -> 0.0). Verified failing on the 0.1.3 code and
passing on the fix under Ruby 3.4.9.
Guard array and serialization vivify paths against coercion
Close the two coverage gaps the v0.1.3 regression exposed beyond
construction/assignment:
- Marshal and YAML round-trips of a number-like string value ("01970"):
init_with and marshal_load both call vivify, so 0.1.3 corrupted
deserialized strings too. These fail on 0.1.3, pass on the fix.
- A number-like string inside an array: vivify_array was never broken,
so this is a forward-guard against reintroducing coercion there.
Revert "Guard array and serialization vivify paths against coercion"
This reverts commit a027343. Those test additions were pushed without
sign-off; backing them out restores the branch to the reviewed state
(regression fix, version bump, and construction/assignment specs).
gillisd
force-pushed
the
claude/fervent-hawking-c4docr
branch
from
June 22, 2026 16:46
adfdbb6 to
1446019
Compare
gillisd
force-pushed
the
claude/fervent-hawking-c4docr
branch
from
June 22, 2026 16:48
1446019 to
b94c12d
Compare
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 broke
v0.1.3 rewrote
Vivification#vivify_valuefrom a class-basedcase/wheninto a pattern-matchingcase/inthat runs every stored value throughINTEGER/FLOAT/DATELIKEregexes:vivify_valueruns on every construction (#initialize→#vivify) and every assignment (#[]=), so this silently corrupts any string containing a digit:Flexor.new(address: "123 Main Street").address"123 Main Street"123Flexor.new(note: "call me at 3pm").note"call me at 3pm"0.0Flexor.new(phone: "555-1234").phone"555-1234"555Flexor.new(ts: "2023-01-15T10:30:00").ts"2023-01-15T10:30:00"2023The branch was internally broken too — the
DATELIKEarm doesrequire "datetime"(no such file; it'sdate) and callsitoutside a block — butINTEGER's[0-9-]+matches date strings first, so that arm was dead code masking two more bugs.Why no test caught it
Every string value in the suite is digit-free (
"alice","deep","localhost","NYC", …), and every digit-bearing datum is either already anInteger(age: 30,id: 1) or nested inside an Array — andvivify_arraywas never changed, so array elements skip the coercion entirely. The coercion code path simply had no exercising test.(The new top-level
patterns_spec.rbadded in the same changeset lived outsidespec/, sorake specnever ran it, and it contained only askip.)Fix
vivify_valueto pass non-Hash/Arrayvalues through unchanged (matching the siblingvivify_array).patterns_spec.rbdebris from the abandoned coercion experiment.Notes
Serialization#init_withto a.then { it[...] }pipeline — is not a real bug on the supported platform.itrefers to the block argument from Ruby 3.4 onward, and the gemspec requires>= 3.4. It's functionally identical to v0.1.2 there.issues.recentry "'Coerce' error when using sum". That issue (Flexor not implementing the numericcoerceprotocol) is separate and still open — it should be fixed without mutating stored data. Worth a follow-up.