Skip to content

engine: coerce CEL results to canonical native values (SPEC §5.1)#41

Merged
fruwe merged 1 commit into
mainfrom
fix-native-boundary-values
Jul 1, 2026
Merged

engine: coerce CEL results to canonical native values (SPEC §5.1)#41
fruwe merged 1 commit into
mainfrom
fix-native-boundary-values

Conversation

@fruwe

@fruwe fruwe commented Jul 1, 2026

Copy link
Copy Markdown
Member

Closes #40. Implements the boundary rule from fruwehq/harel#32 (SPEC §5.1, merged via harel#33).

Problem

CEL-produced values surfaced celpy wrapper types through the public boundary: assign active = active + 1 made resolved_esvs()["active"] a celpy.celtypes.IntType, while a host-seeded int stayed native. Harmless to conformance/--json (the wrappers subclass their natives), but it leaks a guard-language detail — a host doing type(x) is int, isinstance checks, or interop with harel-rust (native scalars) gets a surprise.

Fix

Normalize every CEL result to native Python at the single choke pointcel.evaluate via _from_cel — so no wrapper can escape the module. Covers all kinds (int/float/bool/string/bytes/map/list) and nested containers, which by construction reaches every boundary (esvs, snapshots, --json, observer, published payloads).

Verify

  • Issue repro now returns native int.
  • New tests/test_native_values.py: native type for every esv kind (incl. nested), and no celpy type anywhere in a snapshot.
  • 132 unit + 57 conformance green; ruff + mypy clean.

Implementation-only; spec (harel#32/#33) already merged, and per that spec no new engine conformance case is warranted (cross-language type identity isn't language-neutrally expressible; --json conformance already enforces canonical JSON).

celpy returns its own wrapper types (IntType/DoubleType/BoolType/StringType/
MapType/ListType) which subclass their natives, so they serialized and compared
fine but leaked a guard-language implementation detail through the public boundary
(resolved_esvs, snapshots, --json, observer): 'assign active = active + 1' yielded
celpy.celtypes.IntType instead of int. Normalize every CEL result to native Python
at the single choke point (cel.evaluate, via _from_cel), covering all value kinds
and nested containers. Add unit tests asserting native types for every esv kind
and that snapshots hold no celpy types.

Closes #40.
@fruwe fruwe merged commit e88ff8f into main Jul 1, 2026
2 checks passed
@fruwe fruwe deleted the fix-native-boundary-values branch July 1, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Library API leaks guard-language wrapper types (celpy IntType) instead of native values

1 participant