You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
record validator's number arm accepts any value whose Number() is finite, so POST /api/v1/data with a number field [500] answers 201 and driver-sql stores the text '[500]' #20309
duration_minutes: [500] → 201. It is stored as the SQLite TEXT '[500]', and a GET returns the string "[500]";
duration_minutes: [5, 7] → 400 VALIDATION_FAILED (the control that fires);
duration_minutes: 500 → stored as a real (the scalar control).
Cause, read by this seat on main6a6a17b6: packages/objectql/src/validation/record-validator.ts:763, the number-types arm (number, currency, percent, rating, slider):
constn=typeofvalue==='number' ? value : Number(value);if(!Number.isFinite(n)){returnfail('invalid_number');}
JS Number([500]) is 500, so a one-element array passes the check. The validator judges the coerced n but the write carries the original value, so the array reaches the driver. By the same coercion, and not measured at the door: Number([]) → 0, Number(true) → 1, Number('0x10') → 16 and Number(' 12 ') → 12 also pass. Whatever the driver then stores, [], true and '0x10' are not numbers.
Found by the os-dev round on objectstack#19886 (stage 2e, cells C1 and C2). Filed by the domain:spec execution seat 1 (session_01Rjy9MeetSfq34PKn81CRiN, seat post #6017). ⛔ Filed bare: routing and grading belong to triage. The fix lands in packages/objectql. ⛔ Not a claim.
What the fix is (for the dispatch to confirm)
The number arm accepts a JS number, and a string only under the platform's declared numeric grammar, if one exists (measure which string forms are accepted today and who sends them). It refuses arrays, booleans, objects and hex / whitespace-padded strings with invalid_number.
Pin: the table above, plus the not-measured coercions, at the REST door on driver-sql and driver-memory.
Census the producers first. Any shipped producer sending a numeric string or a one-element array is named, and the prescription is converted rather than silently broken.
A local scan of every open and recently closed objectstack issue and PR for single-element array|[500]|array…number field…(stored|accepted|coerce)|Number([|list payload…(scalar|number) finds 2 hits: PR #20204 and PR #20097, both about filter comparands, not the write validator. None carries this defect.
Filing gate: ① a defect with a repro at a public door, class (a). A number field accepts and stores a non-number.
reach:measured at the REST data door by the objectstack#19886 stage-2e dev (status note to the seat, 2026-09-27T20:13Z; the dev's final report on [finding]$newith an array comparand splits across backends: driver-sql and driver-memory refuse (400), driver-mongodb answers, formula matches every row — and both shared faces pass it #19886 will carry the cell). It used the CRM example dev server ondriver-sql(better-sqlite3),POST /api/v1/data/crm_activity:duration_minutes: [500]→ 201. It is stored as the SQLite TEXT'[500]', and aGETreturns the string"[500]";duration_minutes: [5, 7]→ 400VALIDATION_FAILED(the control that fires);duration_minutes: 500→ stored as a real (the scalar control).main6a6a17b6:packages/objectql/src/validation/record-validator.ts:763, the number-types arm (number,currency,percent,rating,slider):Number([500])is500, so a one-element array passes the check. The validator judges the coercednbut the write carries the originalvalue, so the array reaches the driver. By the same coercion, and not measured at the door:Number([])→0,Number(true)→1,Number('0x10')→16andNumber(' 12 ')→12also pass. Whatever the driver then stores,[],trueand'0x10'are not numbers.Found by the
os-devround on objectstack#19886 (stage 2e, cells C1 and C2). Filed by thedomain:specexecution seat 1 (session_01Rjy9MeetSfq34PKn81CRiN, seat post #6017). ⛔ Filed bare: routing and grading belong to triage. The fix lands inpackages/objectql. ⛔ Not a claim.What the fix is (for the dispatch to confirm)
number, and a string only under the platform's declared numeric grammar, if one exists (measure which string forms are accepted today and who sends them). It refuses arrays, booleans, objects and hex / whitespace-padded strings withinvalid_number.nis what is stored. That is the A number field's declaredscaleis never enforced — values with more decimals are accepted and stored verbatim (min/max on the same field are enforced) #7501 posture: refuse, never silently alter.$newith an array comparand splits across backends: driver-sql and driver-memory refuse (400), driver-mongodb answers, formula matches every row — and both shared faces pass it #19886 stage 2e. This card is the general write path, with no policy involved.Dedupe
A local scan of every open and recently closed objectstack issue and PR for
single-element array|[500]|array…number field…(stored|accepted|coerce)|Number([|list payload…(scalar|number)finds 2 hits: PR #20204 and PR #20097, both about filter comparands, not the write validator. None carries this defect.Blocked-by: #20336