refactor(code-runtime): address seam review — drop worker aliases, tighten dunder

- Worker consumes PORTABLE_RESERVED_WORDS / RESERVED_ERROR_MEMBERS by
  their seam names directly, dropping the local re-alias (symmetry with
  the other two imported constants).
- Split the reserved-vs-duplicate diagnostics: a backend-owned global now
  reports "reserved binding global", not the misleading "duplicate".
- DUNDER_MEMBER uses `__.+__` so a bare `__` (empty middle, not a real
  CPython dunder) is not matched; add coverage.
- Worker misuse tests add `a$b` (second-char `$`) and `lambda` (Python
  keyword) so the identifier narrowing and reserved-word adoption are
  each pinned directly, not only transitively.
- Clarify the seam JSDoc (dunder-vs-explicit-set wording, Python backend
  is a later stack PR) and record in the Agent Note the obligation to
  widen RESERVED_BINDING_GLOBALS when the bootstrap seeds more globals.
This commit is contained in:
Chinesezjc
2026-08-07 11:20:05 +08:00
parent b5578c026e
commit eb03aa86fe
7 changed files with 54 additions and 42 deletions
@@ -790,7 +790,14 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => {
// `$tools` is legal JS but outside the seam's language-portable subset:
// the same namespace list must work against every backend's language.
['$tools', /not a usable identifier/],
['console', /duplicate binding global/],
// `a$b` pins the second character class too: the old identifier regex
// `[A-Za-z0-9_$]*` would have accepted a `$` after the first character.
['a$b', /not a usable identifier/],
// `lambda` is a Python keyword, refused here directly (not just
// transitively) so the worker's adoption of PORTABLE_RESERVED_WORDS is
// its own regression, symmetric with the `$tools` case.
['lambda', /not a usable identifier/],
['console', /reserved binding global/],
]
for (const [global, message] of cases) {
await expect(runtime.run({ program: 'return 1', bindings: [{ global, functions: {} }] })).rejects.toThrow(message)
@@ -817,7 +824,7 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => {
await expect(run([namespace('tools', 'not valid!')])).rejects.toThrow(/error class.*not a usable identifier/)
await expect(run([namespace('tools', 'await')])).rejects.toThrow(/error class.*not a usable identifier/)
await expect(run([namespace('tools', 'console')])).rejects.toThrow(/duplicate injected global/)
await expect(run([namespace('tools', 'console')])).rejects.toThrow(/reserved binding global/)
await expect(run([namespace('tools', 'tools')])).rejects.toThrow(/duplicate injected global/)
await expect(run([
namespace('tools', 'CallError'),
@@ -829,10 +836,10 @@ describe('WorkerCodeRuntime — seam misuse and lifecycle', () => {
// dunders too, so the same errorClass is valid (or not) on every backend.
await expect(run([namespace('tools', 'CallError', 'args')])).rejects.toThrow(/member property.*not usable/)
await expect(run([namespace('tools', 'CallError', '__dict__')])).rejects.toThrow(/member property.*not usable/)
// The Python bootstrap's owned globals are refused here too (shared
// The Python backend's owned globals are refused here too (shared
// RESERVED_BINDING_GLOBALS), keeping namespace lists backend-portable.
await expect(runtime.run({ program: 'return 1', bindings: [{ global: '__dsh_main__', functions: {} }] }))
.rejects.toThrow(/duplicate binding global/)
.rejects.toThrow(/reserved binding global/)
})
it('rejects config values that are not positive numbers', async () => {