fix(tools): correct the trim-order claim and check the Literal escape dependency

trim and escape commute for every input, so the new whitespace test does
not pin their order: UNPRINTABLE and LONE_SURROGATE are disjoint from the
set trim() strips, and both escapes emit plain non-whitespace ASCII,
leaving the leading and trailing whitespace runs byte-identical. State that instead of the false causal clause.

pyScalar's Literal path escapes nothing itself -- JSON.stringify is what
keeps it parseable, covering NUL and, under ES2019 well-formed
stringification, unpaired surrogates. Record the dependency and turn it
into a checked invariant. Pin the docstring emission site for a lone
surrogate too, mirroring the NUL case.

Two docstring corrections: describe's caller enumeration omitted the
synthetic { description } wrapper docLines builds, and "special in
statement position" does not describe `_`, which is special in a match
pattern. Both keep the conclusion they support.

Note which of the two table guards fires depends on the entry point.
This commit is contained in:
Chinesezjc
2026-08-05 18:42:43 +08:00
parent 529e69ed87
commit 9bba851a62
5 changed files with 34 additions and 10 deletions
@@ -37,7 +37,7 @@ The standard that cap serves is grammatical validity, and the boundary is delibe
## Consequences
Adding a backend language is two table entries — an `SDK_RENDERERS` entry and a `RUN_CODE_FLAVORS` entry — plus the renderer function the former points at, with no change to `agent-loop` or the registry structure. The two tables (`SDK_RENDERERS`, `RUN_CODE_FLAVORS`) must stay in step: a language present in one but not the other is a latent inconsistency the `Object.hasOwn` guards turn into a loud failure rather than a wrong-language prompt. The tool layer stays free of any concrete backend dependency, so it lands and is testable on master ahead of the Python protocol and backend.
Adding a backend language is two table entries — an `SDK_RENDERERS` entry and a `RUN_CODE_FLAVORS` entry — plus the renderer function the former points at, with no change to `agent-loop` or the registry structure. The two tables (`SDK_RENDERERS`, `RUN_CODE_FLAVORS`) must stay in step: a language present in one but not the other is a latent inconsistency the `Object.hasOwn` guards turn into a loud failure rather than a wrong-language prompt. Which of the two failures surfaces depends on the entry point, for a language absent from both tables: assembly reports the missing renderer, because `wireSchemas` calls `requireCodeRuntime` before projecting, while the public `schemas()` reaches `run_code`'s language-aware getters first and reports the missing flavor. The tool layer stays free of any concrete backend dependency, so it lands and is testable on master ahead of the Python protocol and backend.
The cost is that the Python branch of both tables is unreachable on this base: `CodeRuntime.language` is set by the loaded backend, the only published backend is `dsh-code-runtime-worker` (`'typescript'`), and the registry reads the loaded runtime rather than a config field, so no assembled application can select `renderToolsSdkPy` or `PYTHON_FLAVOR`. The model-visible surface is therefore unchanged by this note's work until a backend reporting `'python'` is published, and this PR's coverage is unit-level — the renderer output plus the dispatch and rejection paths. The keyless snapshot for the Python model interface belongs to the PR that publishes that backend, because only there does a real `cordis.yml` over published plugins produce a Python assembly; a snapshot example that mounted a fixture runtime here would assert against a test double, which [docs/testing.md](../../../../docs/testing.md) rejects as a substitute for the assembled application transcript.