Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f90705e
docs(codec): specify bounded value extension protocols
bbopen Sep 20, 2026
f9bea9c
test(codec): prototype exact integers and dataclass output
bbopen Sep 20, 2026
4040b74
test(codec): prototype cross-language value extensions
bbopen Sep 20, 2026
e460a4f
test(codec): reject ambiguous prototype envelopes
bbopen Sep 20, 2026
30453fc
test(codec): decode exact requests with declared float nodes
bbopen Sep 20, 2026
8ed94d9
test(codec): align prototype Unicode and version boundaries
bbopen Sep 20, 2026
6e694a7
test(codec): emit the counted Unicode wire form
bbopen Sep 20, 2026
0ad97ce
test(codec): match prototype output bytes to checked limit
bbopen Sep 20, 2026
9a1a4c0
test(codec): reject ordinary class as dataclass output
bbopen Sep 20, 2026
9a00640
test(codec): show serializable unsupported dataclass field
bbopen Sep 20, 2026
80bfa77
test(codec): prove generated Point through dataclass adapter
bbopen Sep 20, 2026
0226fd9
test: use generated camelCase Point callable
bbopen Sep 20, 2026
f76641f
test: derive Point proof from analyzed importable fixture
bbopen Sep 20, 2026
20fa0f6
docs: record exact integer migration costs
bbopen Sep 20, 2026
f835f98
docs: separate proposed policy from prototype checks
bbopen Sep 20, 2026
a84e9b9
test: bind generated Point call to explicit value policy adapter
bbopen Sep 20, 2026
5010dc0
docs: record generated Point proof and remaining boundary
bbopen Sep 20, 2026
58da680
test: pin Point adapter rejection causes
bbopen Sep 20, 2026
18aa8de
docs: mark bigint generator contract gap
bbopen Sep 20, 2026
5b2dc3f
test: pin dataclass input and depth rejection
bbopen Sep 20, 2026
c45aac0
test: add analyzed exact integer callable fixture
bbopen Sep 20, 2026
684b940
test: add private exact integer call adapter
bbopen Sep 20, 2026
bd9efc7
test: keep adapter capability metadata outside request
bbopen Sep 20, 2026
1208322
test: check exact call arguments as one bounded record
bbopen Sep 20, 2026
9aec49f
docs: measure representative exact integer payload growth
bbopen Sep 20, 2026
8d437b7
test: make exact fixture distinguish signed zero
bbopen Sep 20, 2026
d8b29a4
feat(contracts): define pinned exact integer revision 3
bbopen Sep 20, 2026
38c9b84
test: map resolved v3 nodes into prototype codec
bbopen Sep 20, 2026
a3bdc13
feat(codegen): compile exact integers behind v3 capability
bbopen Sep 20, 2026
d6f1bac
test: prove generated exact bigint wrapper through bound provider
bbopen Sep 20, 2026
694bc00
fix(contracts): make recursive revisions typecheck
bbopen Sep 20, 2026
ba138a4
docs: state bounded generated bigint proof and rollout gap
bbopen Sep 20, 2026
d06e4fa
test: prove generated nested exact integer return and request caps
bbopen Sep 20, 2026
42ff1e1
test: reject malformed nested bigint envelope in bound call
bbopen Sep 20, 2026
4f224da
merge: adopt accepted exact integer v3 source
bbopen Sep 20, 2026
9ed30b1
merge: align exact integer proof with release integration
bbopen Sep 20, 2026
577800b
docs: describe both analyzed exact integer callables
bbopen Sep 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 33 additions & 17 deletions docs/maintainers/value-contract-prototypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ import them.

## Exact integer option

The generation option is `integerMode: 'bigint'` for one callable. It maps every
Python `int` parameter and result to TypeScript `bigint`. Safe integers use the
same type. Python `bool` remains `boolean`. Calls without the option keep the
safe `number` rule.

The current value-contract revision represents Python `int` only as a safe JSON
`number`. The compiler and return validator follow that rule. This prototype
does not generate `bigint` wrappers; that needs a deliberate contract extension.
The proposed public option is `integerMode: 'bigint'` for one callable. It would
map every Python `int` parameter and result to TypeScript `bigint`. Safe
integers use the same type. Python `bool` remains `boolean`. Calls without the
option keep the safe `number` rule.

The default value-contract revision 2 represents Python `int` as a safe JSON
`number`. The bounded revision 3 proof selects
`EXACT_INTEGER_VALUE_CONVERSION` for an analyzed Python module. It emits
`bigint` wrappers and validators for scalar and nested results through a
test-only runtime binding. A public per-callable option and production bridge
adapter are not implemented.

The proposed generated wrapper must require `exactIntegerDecimalV2` in the
bridge's `meta.valueCapabilities`. It must send
`params.valuePolicy.integer = 'bigint-v2'` on each call. A new bridge must
reject unknown policies. An old bridge lacks the capability, so the wrapper must
reject the call before sending a tag. The prototype tests this policy in an
isolated adapter. The shipped wrapper does not implement it.
reject the call before sending a tag. The bound proof checks the capability
before its private adapter encodes arguments. That adapter sends the policy to
the Python prototype. The default bridge does not implement this mode.

The version 2 integer envelope is
`{"__tywrap__":"integer","codecVersion":2,"encoding":"decimal","value":"18446744073709551617"}`.
Expand All @@ -46,9 +50,9 @@ rejects malformed float tags and nonfinite numbers.

The Python response encoder tags every `int`, including safe values. The
TypeScript response decoder returns `bigint` at declared integer nodes. The
generated return validator must require `bigint`. It must reject an ordinary
number and a raw tag. Arrow int64 keeps its current Arrow encoding and decoded
type.
generated revision 3 return validator requires `bigint`. The prototype decoder
rejects an ordinary number and a raw tag. Arrow int64 keeps its current Arrow
encoding and decoded type.

Both prototypes walk nested arrays and string-keyed records within depth and
node limits. They reject unsupported values and malformed envelopes. Encoders
Expand All @@ -60,10 +64,16 @@ characters directly, as `JSON.stringify` does. Both paths reject unpaired
surrogates. Production must check raw wire bytes before parsing; object-level
checks do not prove equal byte counts for alternate numeric JSON spellings.

The bounded tests must round trip positive and negative values beyond 64 bits.
They must cover floats, booleans, nested records, malformed tags, digit limits,
byte limits, and old bridges. Production work needs separate review of
capability negotiation, generated types, and migration cost.
The bounded tests round trip positive and negative values beyond 64 bits. They
cover floats, booleans, nested records, malformed tags, digit limits, byte
limits, and old bridges. `test/value_extensions_generated_integer.test.ts` uses
analyzer IR to check `bigint` and `bigint[]` inputs, `Promise<bigint>` and
`Promise<bigint[][]>` outputs, and generated bigint return validation at a
nested index. It checks signed zero, a client request limit before dispatch,
the Python raw input limit, and that an incapable bridge receives no exact
request. The same fixture under revision 2 keeps `number` types and uses an
ordinary call. Production still needs a public opt-in selector, bridge
capability negotiation, and application migration measurements.

### Exact integer migration cost

Expand All @@ -77,6 +87,12 @@ Each tagged integer adds 73 JSON bytes beyond its decimal digits. For example,
Nested collections multiply that cost by their integer count. Teams must measure
representative call payloads against the byte limit before enabling the option.

For a compact `{"args": [...]}` payload with three integers, a boolean, and a
float, the safe-value example grows from 28 to 247 UTF-8 bytes (8.82 times).
Using one 81-bit and one 131-bit integer grows the same shape from 91 to 310
bytes (3.41 times). These figures exclude the surrounding RPC envelope and do
not estimate application traffic.

The client must check the bridge capability before it sends tagged values. This
requires a coordinated client and bridge rollout. Old bridges reject the opted
call. Arrow int64 columns keep their current type and wire format.
Expand Down
14 changes: 14 additions & 0 deletions test/fixtures/python/value_contract_exact_integer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Importable exact-integer fixture for the bounded v3 compiler proof."""

import math


def combine_exact(value: int, nested: list[int], flag: bool, ratio: float) -> int:
"""Combine scalar and nested integers after the bridge decodes them."""
total = value + sum(nested)
return total if flag and math.copysign(1.0, ratio) > 0 else -total


def echo_exact(value: int, nested: list[int]) -> list[list[int]]:
"""Return nested values after the bridge decodes them."""
return [[value], nested, [-value]]
19 changes: 19 additions & 0 deletions test/prototypes/value_contract_v3_adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** Translate resolved v3 nodes into the isolated cross-language test codec. */

import type { ValueContractV3 } from '../../src/contracts/value-contract.js';
import type { PrototypeContract } from './value_extensions.js';

export function toExactPrototypeContract(value: ValueContractV3): PrototypeContract {
switch (value.kind) {
case 'integer-exact':
return { kind: 'integer' };
case 'boolean':
return { kind: 'boolean' };
case 'float':
return { kind: 'float' };
case 'sequence':
return { kind: 'array', item: toExactPrototypeContract(value.item) };
default:
throw new Error(`The exact call fixture cannot use ${value.kind}.`);
}
}
63 changes: 63 additions & 0 deletions test/prototypes/value_exact_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Private Python call adapter for the exact-integer compiler proof."""

from __future__ import annotations

import json
import sys
from typing import Any

from value_contract_exact_integer import combine_exact, echo_exact
from value_extensions import (
MAX_PAYLOAD_BYTES,
PrototypeError,
decode_exact_integers,
encode_exact_integers,
require_capability,
)


def main() -> None:
trusted_contract: dict[str, Any] = json.loads(sys.argv[1])
bridge_meta: dict[str, Any] = json.loads(sys.argv[2])
function_name = sys.argv[3]
functions = {'combine_exact': combine_exact, 'echo_exact': echo_exact}
function = functions.get(function_name)
if function is None:
raise PrototypeError('unknown exact-integer callable')
raw = sys.stdin.buffer.read(MAX_PAYLOAD_BYTES + 1)
if len(raw) > MAX_PAYLOAD_BYTES:
raise PrototypeError('input payload exceeds byte limit')
request: dict[str, Any] = json.loads(raw)
if (request.get('module'), request.get('functionName')) != (
'value_contract_exact_integer',
function_name,
):
raise PrototypeError('unexpected exact-integer callable')
params = request.get('params')
if not isinstance(params, dict):
raise PrototypeError('missing exact-integer call parameters')
value_policy = params.get('valuePolicy')
policy = value_policy.get('integer') if isinstance(value_policy, dict) else None
require_capability(bridge_meta, 'exactIntegerDecimalV2', policy)
args = params.get('args')
fields = trusted_contract.get('fields')
if (
trusted_contract.get('kind') != 'record'
or not isinstance(fields, dict)
or not isinstance(args, list)
or len(args) != len(fields)
):
raise PrototypeError('exact-integer arguments differ from the contract')
input_record = dict(zip(fields, args, strict=True))
decoded = decode_exact_integers(input_record, trusted_contract)
assert isinstance(decoded, dict)
result = function(**decoded)
encoded = encode_exact_integers(result)
wire = json.dumps(
encoded, allow_nan=False, ensure_ascii=False, separators=(',', ':')
).encode('utf-8')
sys.stdout.buffer.write(wire + b'\n')


if __name__ == '__main__':
main()
Loading
Loading