resources: Sandbox.read for a script path known at run time (step 1 of #138) #576

Closed
opened 2026-10-29 08:21:50 +00:00 by orion · 3 comments
Collaborator

Step 1 of the epic #138 (RESOURCES slices 5 and 6).

Goal

std/sandbox gets the member for a script whose path is decided while the program runs: Sandbox.read<Value>(path: Path, capabilities). It is the third verb of RESOURCES.md section 5: read takes a Path, the compiler has never seen the file, nothing is checked at build time, everything at run time. Today's Sandbox.load(path: String) does exactly that for every path the program computes, so this step gives that behaviour its final name and moves every run-time caller to it. load and embedded change their parameter types to Resource / EmbeddedText in later steps of the epic; this step leaves load as it is.

Design record

  • RESOURCES.md section 5 ("Sandbox, which needs all three": "Today's Sandbox.load becomes Sandbox.read"), section 10 slice 5, and URI.md gap table row for Sandbox.embedded/load/read.
  • SCRIPTS.md slice 7 (a script from a path only known while the program runs): behaviour unchanged, only the member that spells it.
  • Verified against main (4b59fae): the dependency of the epic ("Sandbox runs on both implementations") holds. tests/conformance/sandbox-crossing.trb prints the same in the VM and in a native binary, tests/conformance/vm-only/sandbox-*.trb and compiler/tests/sandbox.test.trb exercise the VM, Sandbox.loadText exists. RESOURCES.md probe 4 ("runs on neither implementation") and the "Blocked" cells of slices 5 and 6 are stale.

Acceptance criteria

  • std/sandbox declares static fn read<Value>(path: Path, capabilities: (var self: SandboxCapabilities) => Void = {}): Result<Script<Value>, SandboxError>. It behaves as load does today for a path that no literal named: the file is read relative to the working directory, checked against Value and lowered when the program asks, with the same grants, limits and SandboxError texts (a missing file is There is no script ...). It never consults the table of scripts the program was compiled with, and the checker does not treat a read call as a receiver-script load (a read of a file that does not exist leaves torb check clean).
  • tests/conformance/vm-only/sandbox-runtime-path.trb and the run-time-path cases of tests/conformance/vm-only/sandbox-*.trb and compiler/tests/sandbox.test.trb call read with a Path and keep their .expected byte for byte; a new case shows that read of a literal-looking Path is not checked at build time while load of a literal still is.
  • sandbox-crossing.trb and the literal Sandbox.load cases stay green and unchanged (tier A; tier B only if the change reaches compiler/src/ir, compiler/src/backend or runtime/, which it should not).
  • Docs: docs/standard-library/sandbox.md declaration block lists read (the torb:declaration block stays in sync), docs/language/configuration/the-sandbox.md and SCRIPTS.md slice 7 name read for a path known at run time; RESOURCES.md status header and section 10 row 5 say that slice 5 is in progress and that probe 4 is historical; build/release/torb.exe docs skill docs skills regenerated.

Seed

Does not touch the seed: no syntax change, no new native (read shares the existing loadScript / hostLoadScript natives with load), no driver flag. The compiler recognizes Sandbox.load by its shape (compiler/src/semantics/scripts.trb); it looks up no name read, and compiler/src does not call Sandbox itself. The seed question comes with the later step that changes load's parameter type.

Size

One PR, one Conventional Commit: feat(sandbox): Sandbox.read loads a script from a path known at run time. Worker: sonnet/medium (std/, tests, docs).

Keep out of

compiler/src/semantics/{graph,scripts}.trb, checker/receiver.trb, ir/lower/script.trb: the script-receivers epic #518 (#513) reworks them, and this step needs none of them. Doc files that #517 migrates (sandbox.md, the-sandbox.md) conflict only textually; rebase.

Step 1 of the epic #138 (RESOURCES slices 5 and 6). ## Goal `std/sandbox` gets the member for a script whose path is decided while the program runs: `Sandbox.read<Value>(path: Path, capabilities)`. It is the third verb of [RESOURCES.md section 5](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/RESOURCES.md): `read` takes a `Path`, the compiler has never seen the file, nothing is checked at build time, everything at run time. Today's `Sandbox.load(path: String)` does exactly that for every path the program computes, so this step gives that behaviour its final name and moves every run-time caller to it. `load` and `embedded` change their parameter types to `Resource` / `EmbeddedText` in later steps of the epic; this step leaves `load` as it is. ## Design record - RESOURCES.md section 5 ("`Sandbox`, which needs all three": "Today's `Sandbox.load` becomes `Sandbox.read`"), section 10 slice 5, and URI.md gap table row for `Sandbox.embedded/load/read`. - SCRIPTS.md slice 7 (a script from a path only known while the program runs): behaviour unchanged, only the member that spells it. - Verified against `main` (4b59fae): the dependency of the epic ("`Sandbox` runs on both implementations") holds. `tests/conformance/sandbox-crossing.trb` prints the same in the VM and in a native binary, `tests/conformance/vm-only/sandbox-*.trb` and `compiler/tests/sandbox.test.trb` exercise the VM, `Sandbox.loadText` exists. RESOURCES.md probe 4 ("runs on neither implementation") and the "Blocked" cells of slices 5 and 6 are stale. ## Acceptance criteria - [ ] `std/sandbox` declares `static fn read<Value>(path: Path, capabilities: (var self: SandboxCapabilities) => Void = {}): Result<Script<Value>, SandboxError>`. It behaves as `load` does today for a path that no literal named: the file is read relative to the working directory, checked against `Value` and lowered when the program asks, with the same grants, limits and `SandboxError` texts (a missing file is `There is no script ...`). It never consults the table of scripts the program was compiled with, and the checker does not treat a `read` call as a receiver-script load (a `read` of a file that does not exist leaves `torb check` clean). - [ ] `tests/conformance/vm-only/sandbox-runtime-path.trb` and the run-time-path cases of `tests/conformance/vm-only/sandbox-*.trb` and `compiler/tests/sandbox.test.trb` call `read` with a `Path` and keep their `.expected` byte for byte; a new case shows that `read` of a literal-looking `Path` is not checked at build time while `load` of a literal still is. - [ ] `sandbox-crossing.trb` and the literal `Sandbox.load` cases stay green and unchanged (tier A; tier B only if the change reaches `compiler/src/ir`, `compiler/src/backend` or `runtime/`, which it should not). - [ ] Docs: `docs/standard-library/sandbox.md` declaration block lists `read` (the `torb:declaration` block stays in sync), `docs/language/configuration/the-sandbox.md` and SCRIPTS.md slice 7 name `read` for a path known at run time; RESOURCES.md status header and section 10 row 5 say that slice 5 is in progress and that probe 4 is historical; `build/release/torb.exe docs skill docs skills` regenerated. ## Seed Does not touch the seed: no syntax change, no new native (`read` shares the existing `loadScript` / `hostLoadScript` natives with `load`), no driver flag. The compiler recognizes `Sandbox.load` by its shape (`compiler/src/semantics/scripts.trb`); it looks up no name `read`, and `compiler/src` does not call `Sandbox` itself. The seed question comes with the later step that changes `load`'s parameter type. ## Size One PR, one Conventional Commit: `feat(sandbox): Sandbox.read loads a script from a path known at run time`. Worker: sonnet/medium (`std/`, tests, docs). ## Keep out of `compiler/src/semantics/{graph,scripts}.trb`, `checker/receiver.trb`, `ir/lower/script.trb`: the script-receivers epic #518 (#513) reworks them, and this step needs none of them. Doc files that #517 migrates (`sandbox.md`, `the-sandbox.md`) conflict only textually; rebase.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261029 until 2026-10-29T14:35Z

[loop:torbscript] claim implement by session:loop-torbscript-20261029 until 2026-10-29T14:35Z
Author
Collaborator

[loop:torbscript] implement: PR #577 open, review requested from argus, forge CI queued on the runners (commit messages, change scope and pdisc green; gates, bootstrap and tiers pending after 29 min of waiting, run https://git.torb.dev/torbscript/language/actions/runs/2209), next: waiting (forge CI and merge gate). One deviation from the acceptance criteria, explained in the PR: a Path is normalized, so the missing-file line of sandbox-runtime-path.expected now names generated/nowhere.trb instead of ./generated/nowhere.trb; every other line is byte for byte. compiler/tests/sandbox.test.trb has no run-time-path case, so it is unchanged. Worker usage: about 120k tokens (estimate, sonnet).

[loop:torbscript] implement: PR https://git.torb.dev/torbscript/language/pulls/577 open, review requested from argus, forge CI queued on the runners (commit messages, change scope and pdisc green; gates, bootstrap and tiers pending after 29 min of waiting, run https://git.torb.dev/torbscript/language/actions/runs/2209), next: waiting (forge CI and merge gate). One deviation from the acceptance criteria, explained in the PR: a `Path` is normalized, so the missing-file line of `sandbox-runtime-path.expected` now names `generated/nowhere.trb` instead of `./generated/nowhere.trb`; every other line is byte for byte. `compiler/tests/sandbox.test.trb` has no run-time-path case, so it is unchanged. Worker usage: about 120k tokens (estimate, sonnet).
Author
Collaborator

[loop:torbscript] claim fix by session:loop-torbscript-20261029 until 2026-10-29T15:58Z

[loop:torbscript] claim fix by session:loop-torbscript-20261029 until 2026-10-29T15:58Z
argus closed this issue 2026-10-29 12:56:16 +00:00
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#576
No description provided.