Repository navigation
Patch test op: distinguish JSON boolean from number in Python - #187
brightbeamarsalan merged 1 commit into
Conversation
Python's `bool` is a subclass of `int`, so `True == 1` and `False == 0` evaluate as equal. The RFC 6902 `test` operation used bare `!=` to compare values, which made the Python reference accept a patch the TypeScript reference correctly rejects — a cross-language consensus violation that diverges audit chains when the same `decide.override` is replayed against both coordinators. Add `_json_equal()` — a JSON-type-aware deep comparator that checks `isinstance(…, bool)` before falling through to `==`, mirroring the TS `deepEqual` which distinguishes via `typeof`. Apply the fix in both `coordinator-py` and `chap-analytics`. Add conformance vectors (accept + reject) so both references are held to the same rule going forward. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
The current-head CI workflow is awaiting maintainer approval and has not run. Could a maintainer approve the validation workflow so the shared Python/TypeScript patch vectors can be checked upstream? The Copilot quota notice is not a code-review result, and no automated review pass is being claimed. |
brightbeamarsalan
left a comment
There was a problem hiding this comment.
Thanks Dev, good catch. I reproduced it on main: a decide.override whose test op compares true with 1 completed in the Python coordinator and was refused with -32012 in TypeScript. With this change both coordinators refuse it with the same code and message, and the new vectors hold both to that rule. The Python coordinator, chap-analytics and TypeScript patch tests pass locally. I’ll squash-merge once CI is green, and the fix will ship in 0.3.3 and chap-analytics 0.2.4.
Summary
testoperation in both Python references (coordinator-py,chap-analytics) used bare!=to compare values. Python'sboolis a subclass ofint, soTrue == 1andFalse == 0evaluate as equal — but JSON distinguishes them:trueis a boolean,1is a number. The TypeScript reference'sdeepEqualcorrectly distinguishes types viatypeof.decide.overridecarrying atestop that compares a boolean against a number (e.g.{"op": "test", "path": "/confident", "value": true}against actual value1) succeeds in Python but fails in TypeScript — a cross-language consensus violation that produces divergent audit chains from identical inputs._json_equal()— a JSON-type-aware deep comparator that checksisinstance(…, bool)before falling through to==, mirroring the TSdeepEqual. Applied in bothcoordinator-pyandchap-analytics. Added 7 conformance vectors (2 accept, 5 reject) tojson-patch-vectors.jsonso both references are held to the same rule.Reproducer
End-to-end through the coordinator: the same
decide.overrideenvelope produces{"result": {"state": "completed"}}in Python but{"error": {"code": -32012}}in TypeScript.Prior art in the repo
The whisper profile's
_same_value()(whisper.py:29-42) already handles this pattern correctly — it checksisinstance(a, bool)before comparing. The JSON Patchtestop was the remaining site where the check was missing.Test plan
decide.overridenow agrees across both coordinators🤖 Generated with Claude Code