Summary
Boolean values written to a document round-trip back as int because the type-inference dispatch in _infer_scalar_type checks int before bool, and bool is a subclass of int in Python — so True and False always match the int branch
first and are stored as Int.
Reproduction
from automerge import Document
doc = Document()
with doc.change() as d:
d["flag"] = True
value = doc["flag"]
print(type(value), value)
# actual: <class 'int'> 1
# expected: <class 'bool'> True
Code reference
src/automerge/document.py:555-569 — _infer_scalar_type:
def _infer_scalar_type(value: core.ScalarValue) -> core.ScalarType:
if isinstance(value, str):
return core.ScalarType.Str
elif isinstance(value, bytes):
return core.ScalarType.Bytes
elif isinstance(value, int): # matches True/False first
return core.ScalarType.Int
elif isinstance(value, float):
return core.ScalarType.F64
elif isinstance(value, bool): # unreachable
return core.ScalarType.Boolean
...
Impact
Any document that stores booleans loses type information at the Python boundary. Downstream code doing if doc["flag"] is True or type(doc["flag"]) is bool silently breaks. Sync-protocol interop with JS/Rust peers that write Boolean scalars is
unaffected on read, but new writes from Python end up as Int.
Environment
Reproduced on main at f72374e.
Summary
Boolean values written to a document round-trip back as
intbecause the type-inference dispatch in_infer_scalar_typechecksintbeforebool, andboolis a subclass ofintin Python — soTrueandFalsealways match theintbranchfirst and are stored as
Int.Reproduction
Code reference
src/automerge/document.py:555-569—_infer_scalar_type:Impact
Any document that stores booleans loses type information at the Python boundary. Downstream code doing
if doc["flag"] is Trueortype(doc["flag"]) is boolsilently breaks. Sync-protocol interop with JS/Rust peers that writeBooleanscalars isunaffected on read, but new writes from Python end up as
Int.Environment
Reproduced on
mainat f72374e.