docs(tools): record the case-mapping read point and narrow the class-name quantifier
`camelCase`'s `toUpperCase()` is a fourth reader of the engine's Unicode tables, on a table distinct from XID membership and with a wider window: a tool named U+019B passes `isBareIdentifier` and compiles as `async def` on CPython 3.9.6, but Node maps the head to U+A7DC and the declared `class Args` fails there with `invalid non-printable character`. Record it alongside the three XID read points in the renderer docs and in the note's CPython-floor obligation, and pin the derivation with a test. Correct three over-quantified sentences: a `camelCase`-derived class name is evaluated for every tool but only reaches emitted text when some object shape in the schema declares a `TypedDict`. Attribute the `str.isidentifier()` equivalence to `IDENTIFIER` rather than to the predicate, which is deliberately stricter, and restore the antecedent the mode qualification dropped.
This commit is contained in:
@@ -43,4 +43,4 @@ The cost is that the Python branch of both tables is unreachable on this base: `
|
||||
|
||||
Two runtime contracts the Python SDK text asserts are owed by that same backend PR. First, the instructions tell the model that exactly `tools` and `ToolCallError` are bound and that the declared `TypedDict` classes are not, so the backend must inject those two names — with `ToolCallError.toolName` populated per the seam's `errorClass` contract — and must NOT bind the declared class names into the program's globals; injecting them "helpfully" would make the SDK text false. Second, the language has to be bound to the request: `requireCodeRuntime` resolves `ctx.codeRuntime` separately at assembly and at `run_code` execution, so a reload that swapped the runtime between those two points would hand a program written against one flavor to the other. The split is finer than those two points — `run_code`'s `description` and `parameters` getters each call `resolveFlavor(peekRuntime())`, and `schemaOf` destructures both, so one projection reads the runtime twice; both reads are for `run_code`'s own schema, since the getters are installed on that one definition and every other definition carries plain data properties. A reload between those two reads yields a single schema whose two halves name different languages. Neither is reachable here — one published backend means both reads return the same flavor and no program ever runs against this renderer's output — and the cross-language rejection is not testable until a second language exists.
|
||||
|
||||
Third, that PR owns the CPython floor, and with it the renderer's Unicode-table skew. Three regexes read the running engine's tables (Node 22.23.1: Unicode 17.0) while the interpreter uses its own (CPython 3.9.6: 13.0.0): `isBareIdentifier`'s `IDENTIFIER`, and `camelCase`'s split set and head test. An interpreter older than the engine is the failing direction — a character added to `XID_Start` or `XID_Continue` in between is emitted and its tokenizer refuses the whole block — and it arrives by two independent paths. Through the predicate, a bare method or field name. Through `camelCase`, a class name, which is emitted for every tool including one the predicate rejected: `zz-` plus U+1E4D0 never reaches the predicate's skew, since the `-` rejects it outright, yet it still declares `class Zz𞓐xArgs`. The exposure window is exactly the characters added between the two versions, so the PR that names a supported CPython range must decide explicitly between accepting it and pinning all three read points to tables for that floor — pinning the predicate alone leaves the class-name path open. Nothing here can decide it: the floor does not exist yet, and a table pinned to a guess would be a deployment-varying constant with no configurability behind it.
|
||||
Third, that PR owns the CPython floor, and with it the renderer's Unicode-table skew. Four expressions read the running engine's tables (Node 22.23.1: Unicode 17.0) while the interpreter uses its own (CPython 3.9.6: 13.0.0): `isBareIdentifier`'s `IDENTIFIER`, and `camelCase`'s split set, head test, and `toUpperCase()`. An interpreter older than the engine is the failing direction — the engine emits a character its tokenizer refuses, taking the whole block down — and it arrives by three independent paths. Through the predicate, a bare method or field name headed or tailed by a character added to `XID_Start`/`XID_Continue` between the two versions. Through `camelCase`'s XID reads, a class name, which reaches emitted text whenever any object shape in the tool's schema declares a `TypedDict`, and which the predicate's verdict on the tool name does not gate: `zz-` plus U+1E4D0 never reaches the predicate's skew, since the `-` rejects it outright, yet it still declares `class Zz𞓐xArgs`. Through the case mapping, a class name derived from a tool the predicate accepted — a different table and a wider window than XID membership: U+019B is XID_Start and NFKC-stable, so `async def ƛ` compiles on 3.9.6, but Node uppercases it to U+A7DC (unassigned there; CPython's own `.upper()` is the identity) and `class Args` fails with `invalid non-printable character U+A7DC`. The exposure window is the characters and mappings that changed between the two versions, so the PR that names a supported CPython range must decide explicitly between accepting it and pinning all four read points to tables for that floor — pinning the predicate alone leaves both class-name paths open. Nothing here can decide it: the floor does not exist yet, and a table pinned to a guess would be a deployment-varying constant with no configurability behind it.
|
||||
|
||||
Reference in New Issue
Block a user