Split out of #28 (flagged in its audit as a knowingly-shipped follow-up).
create() hydrates the model it caches from Arr::merge($attributes, $ids) — the write-consistent hydration from #25, which is correct and stays. But the caller's scalar types ride along: an int written into a VARCHAR column serves as an int from the pre-warmed cache entry and as a string from a DB read, so a value's type can flap with cache state.
Siren contains the one observed case at the model boundary (Novatorius/siren#196, Config::getValue()), but the general fix belongs here: attribute hydration should normalize values to column types (via the Table column definitions) before building the model, so cache hits and DB reads are byte-identical. Driver differences (PDO native prepares vs emulated, DECIMAL-as-string, etc.) are the hard part and why this wasn't folded into #28.
🤖 Generated with Claude Code
Split out of #28 (flagged in its audit as a knowingly-shipped follow-up).
create()hydrates the model it caches fromArr::merge($attributes, $ids)— the write-consistent hydration from #25, which is correct and stays. But the caller's scalar types ride along: an int written into a VARCHAR column serves as an int from the pre-warmed cache entry and as a string from a DB read, so a value's type can flap with cache state.Siren contains the one observed case at the model boundary (Novatorius/siren#196,
Config::getValue()), but the general fix belongs here: attribute hydration should normalize values to column types (via theTablecolumn definitions) before building the model, so cache hits and DB reads are byte-identical. Driver differences (PDO native prepares vs emulated, DECIMAL-as-string, etc.) are the hard part and why this wasn't folded into #28.🤖 Generated with Claude Code