resources: shipping (RESOURCES slice 3) #136

Closed
opened 2026-10-05 21:07:24 +00:00 by orion · 10 comments
Collaborator

Goal

A Resource (RESOURCES.md section 4) can be read while the program runs: torb build ships the files that Resource literals name to build/<profile>/<program>.resources/<stable name>, and Resource.bytes() / Resource.text() read them relative to the running program (never the working directory), failing with a ResourceError.

Source

What exists on main (verified)

  • Slice 1: std/resource has Resource, EmbeddedBytes, EmbeddedText; the checker resolves a literal and records the stable name; EmbeddedText.text() reads a native embeddedText.
  • The program's own location is already a platform call on every platform: CurrentProcess.executable() (runtime/process.c, runtime/platform.c; /proc/self/exe, GetModuleFileNameW, _NSGetExecutablePath, KERN_PROC_PATHNAME). The "medium risk" of the design record (a platform call on each platform) is therefore already paid.
  • Missing: ResourceError, Resource.bytes()/text(), any .resources/ directory in the build.

Scope

One PR, two Conventional Commits:

  1. feat(resource): read a shipped resource beside the program: ResourceError (at least: not shipped, unreadable, not UTF-8 with the offset of the first bad byte, program location unknown), Resource.bytes(): Task<Result<Bytes, ResourceError>> and Resource.text(): Task<Result<String, ResourceError>>. The directory is <directory of the executable>/<program file name>.resources/<stable name>, / separators on every platform. Prefer composing CurrentProcess.executable() with the existing file read over a new native; the Task is already complete when returned (native targets).
  2. feat(build): ship the files of Resource literals beside the binary: torb build/run copy every file a Resource literal of the checked program names (once per stable name, normalised) to <output>.resources/<stable name>. Only Resource (not Embedded*). Stale files are not cleaned up here.

Acceptance criteria

  • A program that reads Resource literal "./data.txt" with .text() prints the file's content after torb build and running the binary from a different working directory, on Linux (CI) and by construction on every platform (no per-platform code beyond CurrentProcess.executable()).
  • build/<profile>/<program>.resources/<owner>/<name>/<path> exists after the build, with the same bytes; two literals reaching one file produce one copy.
  • A binary moved without its .resources/ directory: bytes() returns Err with the stable name in the message (name() spelling identical on both implementations), never a panic.
  • text() on a non-UTF-8 file is a ResourceError carrying the offset of the first bad byte, never a replacement character.
  • Conformance programs (byte-identical on both implementations, .expected files include the stable name): shipped resource read ok, shipped resource missing at run time, binary (non-UTF-8) via bytes(), program printing a resource's name.
  • std/resource tests and docs/standard-library/resource.md (new) updated; docs/tooling/torb-build.md names the .resources/ layout; skills/ regenerated.
  • sh tools/gates.sh a green in forge CI.

Out of scope (other slices)

Lock settings resource lines, --watch, embedded total/budget (#137); ResourceDirectory (#99); Sandbox.load (slices 5 and 6, #138); the web target's fetch (RESOURCES section 9, "later"); the VM reading from the source tree (milestone 7: torb run builds natively today).

Seed impact

No syntax change, no new driver flag. Expected no new native (composed from CurrentProcess.executable() and the file read); if the implementer needs one, say so in the PR body (seed refresh stays Torben's).

Size

One PR, two commits; estimate 3-4 h (std/resource + one build step + conformance).

Dependencies

None unmerged. Slices 1 (std/resource) and CurrentProcess.executable() are on main.

## Goal A `Resource` (RESOURCES.md section 4) can be read while the program runs: `torb build` ships the files that `Resource` literals name to `build/<profile>/<program>.resources/<stable name>`, and `Resource.bytes()` / `Resource.text()` read them relative to the running program (never the working directory), failing with a `ResourceError`. ## Source - [RESOURCES.md slice 3](https://git.torb.dev/torbscript/language/src/branch/main/docs/design/RESOURCES.md) (sections 4, 6 "The stable name", 9, 10). The design record is the specification. - Unblocks #99, #100, #137. ## What exists on main (verified) - Slice 1: `std/resource` has `Resource`, `EmbeddedBytes`, `EmbeddedText`; the checker resolves a literal and records the stable name; `EmbeddedText.text()` reads a native `embeddedText`. - The program's own location is already a platform call on every platform: `CurrentProcess.executable()` (`runtime/process.c`, `runtime/platform.c`; `/proc/self/exe`, `GetModuleFileNameW`, `_NSGetExecutablePath`, `KERN_PROC_PATHNAME`). The "medium risk" of the design record (a platform call on each platform) is therefore already paid. - Missing: `ResourceError`, `Resource.bytes()`/`text()`, any `.resources/` directory in the build. ## Scope One PR, two Conventional Commits: 1. `feat(resource): read a shipped resource beside the program`: `ResourceError` (at least: not shipped, unreadable, not UTF-8 with the offset of the first bad byte, program location unknown), `Resource.bytes(): Task<Result<Bytes, ResourceError>>` and `Resource.text(): Task<Result<String, ResourceError>>`. The directory is `<directory of the executable>/<program file name>.resources/<stable name>`, `/` separators on every platform. Prefer composing `CurrentProcess.executable()` with the existing file read over a new native; the `Task` is already complete when returned (native targets). 2. `feat(build): ship the files of Resource literals beside the binary`: `torb build`/`run` copy every file a `Resource` literal of the checked program names (once per stable name, normalised) to `<output>.resources/<stable name>`. Only `Resource` (not `Embedded*`). Stale files are not cleaned up here. ## Acceptance criteria - [ ] A program that reads `Resource` literal `"./data.txt"` with `.text()` prints the file's content after `torb build` and running the binary from a different working directory, on Linux (CI) and by construction on every platform (no per-platform code beyond `CurrentProcess.executable()`). - [ ] `build/<profile>/<program>.resources/<owner>/<name>/<path>` exists after the build, with the same bytes; two literals reaching one file produce one copy. - [ ] A binary moved without its `.resources/` directory: `bytes()` returns `Err` with the stable name in the message (`name()` spelling identical on both implementations), never a panic. - [ ] `text()` on a non-UTF-8 file is a `ResourceError` carrying the offset of the first bad byte, never a replacement character. - [ ] Conformance programs (byte-identical on both implementations, `.expected` files include the stable name): shipped resource read ok, shipped resource missing at run time, binary (non-UTF-8) via `bytes()`, program printing a resource's `name`. - [ ] `std/resource` tests and `docs/standard-library/resource.md` (new) updated; `docs/tooling/torb-build.md` names the `.resources/` layout; `skills/` regenerated. - [ ] `sh tools/gates.sh a` green in forge CI. ## Out of scope (other slices) Lock `settings` `resource` lines, `--watch`, embedded total/budget (#137); `ResourceDirectory` (#99); `Sandbox.load` (slices 5 and 6, #138); the web target's `fetch` (RESOURCES section 9, "later"); the VM reading from the source tree (milestone 7: `torb run` builds natively today). ## Seed impact No syntax change, no new driver flag. Expected no new native (composed from `CurrentProcess.executable()` and the file read); if the implementer needs one, say so in the PR body (seed refresh stays Torben's). ## Size One PR, two commits; estimate 3-4 h (std/resource + one build step + conformance). ## Dependencies None unmerged. Slices 1 (`std/resource`) and `CurrentProcess.executable()` are on `main`.
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop), source RESOURCES.md slice 3, not a duplicate. Run time and platform work (every platform); unblocks #99, #100, #137. No dependencies. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z

[loop:torbscript] intake: in scope (author orion, label loop), source RESOURCES.md slice 3, not a duplicate. Run time and platform work (every platform); unblocks #99, #100, #137. No dependencies. next: waiting (refine queued, ready buffer full) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261027-0718 until 2026-10-27T09:46Z

[loop:torbscript] claim refine by session:loop-torbscript-20261027-0718 until 2026-10-27T09:46Z
Author
Collaborator

[loop:torbscript] decided by the loop: not an epic. The design record rates slice 3 medium because "where is my own binary" is a platform call per platform, but CurrentProcess.executable() already exists on Linux, Windows, macOS and FreeBSD, so the slice reduces to std/resource (ResourceError, bytes(), text()) plus one build copy step: one PR, two commits. Packaging extras (lock lines, watch, budget) stay in #137, the web fetch stays "later" per RESOURCES.md section 9. Seed impact: none expected (no new native planned).

[loop:torbscript] refine: body rewritten (goal, testable criteria, design pointer, seed impact no, size 1 PR / 2 commits), label ready set, claim released, next: implement. Worker usage: roughly 60k tokens.

[loop:torbscript] decided by the loop: not an epic. The design record rates slice 3 medium because "where is my own binary" is a platform call per platform, but `CurrentProcess.executable()` already exists on Linux, Windows, macOS and FreeBSD, so the slice reduces to std/resource (`ResourceError`, `bytes()`, `text()`) plus one build copy step: one PR, two commits. Packaging extras (lock lines, watch, budget) stay in #137, the web `fetch` stays "later" per RESOURCES.md section 9. Seed impact: none expected (no new native planned). [loop:torbscript] refine: body rewritten (goal, testable criteria, design pointer, seed impact no, size 1 PR / 2 commits), label `ready` set, claim released, next: implement. Worker usage: roughly 60k tokens.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261027-0718 until 2026-10-27T13:56Z

[loop:torbscript] claim implement by session:loop-torbscript-20261027-0718 until 2026-10-27T13:56Z
Author
Collaborator

[loop:torbscript] implement checkpoint (claim kept): branch loop/136-resources-shipping pushed, no PR yet. Worktree code/wt/torbscript-language-136-resources-shipping.

Done (checked with a nightly torb check / torb format --check, both clean; no gates or bootstrap run locally):

  • commit 1 feat(resource): read a shipped resource beside the program: std/resource/src/error.trb (ResourceError: NotShipped, Unreadable, NotUtf8(offset), Unlocated; messages carry the stable name and no machine path), Resource.bytes() / text() composed from CurrentProcess.executable() + File.readBytes (<exe minus .exe>.resources/<stable name>), no new native.
  • WIP commit (to be squashed into commit 2): checker records the file of each Resource literal (CheckedLiteral.source, Checker.shippedResources(): Map<stable name, path>).

Finding: the issue text says "torb run builds natively today", which is stale: torb run defaults to the VM, and the VM answers CurrentProcess.executable() with the entry .trb, so <entry>.trb.resources/ would not exist and the conformance VM leg could not read a resource. Plan: in compiler/src/vm/run.trb runModules, when shippedResources() is non-empty and the run is not a test run, stage the files under a cache directory (File.copy) and hand the VM that staged path as executable (documented pitfall in std/os process docs); torb build ships after a successful link via the same helper (compiler/src/cli/resources.trb, File.copy, File.createDirectory creates parents).

Next steps: (1) std/resource/tests (Err path: not shipped, name in message), (2) compiler/src/cli/resources.trb + call in buildProgram after link + VM staging, (3) four conformance programs (ok, missing at run time, binary via bytes(), name) with .expected incl. stable name, resource fixture files, (4) docs/standard-library/resource.md (exists, update), docs/tooling/torb-build.md layout, torb docs skill docs skills, tools/check-commits.sh, (5) PR Closes #136, review request argus, ci-wait.

Worker usage: roughly 330k tokens so far.

[loop:torbscript] implement checkpoint (claim kept): branch `loop/136-resources-shipping` pushed, no PR yet. Worktree `code/wt/torbscript-language-136-resources-shipping`. Done (checked with a nightly `torb check` / `torb format --check`, both clean; no gates or bootstrap run locally): - commit 1 `feat(resource): read a shipped resource beside the program`: `std/resource/src/error.trb` (`ResourceError`: `NotShipped`, `Unreadable`, `NotUtf8(offset)`, `Unlocated`; messages carry the stable name and no machine path), `Resource.bytes()` / `text()` composed from `CurrentProcess.executable()` + `File.readBytes` (`<exe minus .exe>.resources/<stable name>`), no new native. - WIP commit (to be squashed into commit 2): checker records the file of each `Resource` literal (`CheckedLiteral.source`, `Checker.shippedResources(): Map<stable name, path>`). Finding: the issue text says "`torb run` builds natively today", which is stale: `torb run` defaults to the VM, and the VM answers `CurrentProcess.executable()` with the entry `.trb`, so `<entry>.trb.resources/` would not exist and the conformance VM leg could not read a resource. Plan: in `compiler/src/vm/run.trb` `runModules`, when `shippedResources()` is non-empty and the run is not a test run, stage the files under a cache directory (`File.copy`) and hand the VM that staged path as executable (documented pitfall in `std/os` process docs); `torb build` ships after a successful link via the same helper (`compiler/src/cli/resources.trb`, `File.copy`, `File.createDirectory` creates parents). Next steps: (1) `std/resource/tests` (Err path: not shipped, name in message), (2) `compiler/src/cli/resources.trb` + call in `buildProgram` after link + VM staging, (3) four conformance programs (ok, missing at run time, binary via `bytes()`, `name`) with `.expected` incl. stable name, resource fixture files, (4) `docs/standard-library/resource.md` (exists, update), `docs/tooling/torb-build.md` layout, `torb docs skill docs skills`, `tools/check-commits.sh`, (5) PR `Closes #136`, review request `argus`, ci-wait. Worker usage: roughly 330k tokens so far.
Author
Collaborator

[loop:torbscript] claim implement (continuation 1, from the checkpoint of comment 7441, pinned on anthropic:notahumanmate) by session:loop-torbscript-20261027-0718 until 2026-10-27T14:06Z

[loop:torbscript] claim implement (continuation 1, from the checkpoint of comment 7441, pinned on anthropic:notahumanmate) by session:loop-torbscript-20261027-0718 until 2026-10-27T14:06Z
Author
Collaborator

[loop:torbscript] implement checkpoint 2 (claim kept, continuation 1 ran out of context): branch loop/136-resources-shipping pushed (3 commits: feat(resource), wip checker records, wip shipping+staging+conformance), no PR yet. Worktree code/wt/torbscript-language-136-resources-shipping.

Done since checkpoint 1 (only formatted with a nightly torb format; torb check compiler was started in the background, log /tmp/rs-136/check-compiler.log, result not yet read):

  • compiler/src/cli/resources.trb: shipResources (writes <program minus .exe>.resources/<stable name> from the bytes the checker saw, workspace.resource(path) + File.writeBytes), stageResources (VM: <cache>/resources/<hash of entry>/<entry name> as the name the program runs under), resourceDirectoryOf.
  • cli/build.trb buildProgram: checker.shippedResources() after lowering, ship after a successful link, not for options.testing (a test run ships nothing in VM and native, so the std/resource tests can assert the NotShipped path in both). cli/embed.trb (--embed-vm) ships beside its binary too.
  • vm/run.trb: bytecodeOf (no caller left) removed; runModules uses machineLoweringOf, MachineLowering.resources added, stages when !isTestRun and resources exist and hands the staged path to runProgram as executable.
  • std/resource/tests/resource.test.trb: NotShipped for text() and bytes() (name in message), show() of all four errors.
  • tests/conformance/resource-{name,text,bytes,missing}.trb + fixtures resource-files/{note.txt,pattern.bin}; .expected/.exit NOT written yet.

Next steps: (1) read check-compiler.log and fix errors (watch: Map iteration for (name, path) in resources, File.createDirectory creating parents, shipResources return Result<Int, String>); (2) verify the conformance programs' logic with the nightly by faking the shipped dir (<entry>.trb.resources/<stable name>), write .expected (stable name is torbscript/conformance/resource-files/note.txt if the package directory resolves that way, check) and .exit (0); .allocations cannot be measured locally: push without, read the count from the red conformance job, add them; (3) docs: docs/standard-library/resource.md (ResourceError, bytes/text, shipping; drop "next two slices"), docs/tooling/torb-build.md (<program>.resources/ layout, tests ship nothing, --embed-vm ships), docs/standard-library/os.md/std/os process.trb executable() doc (VM answers the staged path for a program with Resource literals), docs/design/RESOURCES.md section 9 VM paragraph (stale "torb run builds natively") + slice 3 row Done, docs/ROADMAP.md resources row; then build/release/torb docs skill docs skills is a gate (CI only): regenerate with nightly torb docs skill docs skills if it works, else expect the CI red to show the diff; (4) squash the two wip commits into commit 2 (feat(build): ship the files of Resource literals beside the binary, <=100 chars), tools/check-commits.sh; (5) PR Closes #136, review argus, one ci-wait.

Worker usage: roughly 620k tokens so far (330k + ~290k this continuation).

[loop:torbscript] implement checkpoint 2 (claim kept, continuation 1 ran out of context): branch `loop/136-resources-shipping` pushed (3 commits: feat(resource), wip checker records, wip shipping+staging+conformance), no PR yet. Worktree `code/wt/torbscript-language-136-resources-shipping`. Done since checkpoint 1 (only formatted with a nightly `torb format`; `torb check compiler` was started in the background, log `/tmp/rs-136/check-compiler.log`, result not yet read): - `compiler/src/cli/resources.trb`: `shipResources` (writes `<program minus .exe>.resources/<stable name>` from the bytes the checker saw, `workspace.resource(path)` + `File.writeBytes`), `stageResources` (VM: `<cache>/resources/<hash of entry>/<entry name>` as the name the program runs under), `resourceDirectoryOf`. - `cli/build.trb` `buildProgram`: `checker.shippedResources()` after lowering, ship after a successful link, **not** for `options.testing` (a test run ships nothing in VM and native, so the `std/resource` tests can assert the `NotShipped` path in both). `cli/embed.trb` (`--embed-vm`) ships beside its binary too. - `vm/run.trb`: `bytecodeOf` (no caller left) removed; `runModules` uses `machineLoweringOf`, `MachineLowering.resources` added, stages when `!isTestRun` and resources exist and hands the staged path to `runProgram` as executable. - `std/resource/tests/resource.test.trb`: NotShipped for `text()` and `bytes()` (name in message), `show()` of all four errors. - `tests/conformance/resource-{name,text,bytes,missing}.trb` + fixtures `resource-files/{note.txt,pattern.bin}`; `.expected`/`.exit` NOT written yet. Next steps: (1) read check-compiler.log and fix errors (watch: `Map` iteration `for (name, path) in resources`, `File.createDirectory` creating parents, `shipResources` return `Result<Int, String>`); (2) verify the conformance programs' logic with the nightly by faking the shipped dir (`<entry>.trb.resources/<stable name>`), write `.expected` (stable name is `torbscript/conformance/resource-files/note.txt` if the package directory resolves that way, check) and `.exit` (0); `.allocations` cannot be measured locally: push without, read the count from the red `conformance` job, add them; (3) docs: `docs/standard-library/resource.md` (ResourceError, bytes/text, shipping; drop "next two slices"), `docs/tooling/torb-build.md` (`<program>.resources/` layout, tests ship nothing, `--embed-vm` ships), `docs/standard-library/os.md`/`std/os` process.trb `executable()` doc (VM answers the staged path for a program with Resource literals), `docs/design/RESOURCES.md` section 9 VM paragraph (stale "torb run builds natively") + slice 3 row Done, `docs/ROADMAP.md` resources row; then `build/release/torb docs skill docs skills` is a gate (CI only): regenerate with nightly `torb docs skill docs skills` if it works, else expect the CI red to show the diff; (4) squash the two wip commits into commit 2 (`feat(build): ship the files of Resource literals beside the binary`, <=100 chars), `tools/check-commits.sh`; (5) PR `Closes #136`, review `argus`, one ci-wait. Worker usage: roughly 620k tokens so far (330k + ~290k this continuation).
Author
Collaborator

[loop:torbscript] implement checkpoint 2 addendum: torb check compiler (nightly) is clean (410 files, no problems) after a fourth wip commit (const _ = on the staged file count); branch pushed. Remaining are steps (2)-(5) above (4 wip commits to squash into commit 2).

[loop:torbscript] implement checkpoint 2 addendum: `torb check compiler` (nightly) is clean (410 files, no problems) after a fourth wip commit (`const _ =` on the staged file count); branch pushed. Remaining are steps (2)-(5) above (4 wip commits to squash into commit 2).
Author
Collaborator

[loop:torbscript] implement: PR open #533 (Closes #136, review requested from argus). Branch rebased on main and squashed into two commits (feat(resource), feat(build)); tools/check-commits.sh clean, .expected/.exit of the four conformance programs written (checked with the nightly VM against this branch's std), docs and skills/ regenerated (second regeneration after the rebase: no diff). Forge CI of 24211457 is running; .allocations of the four programs are added from the CI output if that is all that is red. Claim kept. Worker usage so far roughly 0.8M tokens.

[loop:torbscript] implement: PR open https://git.torb.dev/torbscript/language/pulls/533 (`Closes #136`, review requested from argus). Branch rebased on main and squashed into two commits (feat(resource), feat(build)); `tools/check-commits.sh` clean, `.expected`/`.exit` of the four conformance programs written (checked with the nightly VM against this branch's std), docs and `skills/` regenerated (second regeneration after the rebase: no diff). Forge CI of 24211457 is running; `.allocations` of the four programs are added from the CI output if that is all that is red. Claim kept. Worker usage so far roughly 0.8M tokens.
Author
Collaborator

[loop:torbscript] release implement: the continuation worker timed out while waiting for CI; PR #533 (head 24211457, review requested from argus) carries all its work. next: waiting (CI on PR #533); red CI (e.g. missing .allocations of the four conformance programs) gets a fix worker from the PR state.

[loop:torbscript] release implement: the continuation worker timed out while waiting for CI; PR #533 (head 24211457, review requested from argus) carries all its work. next: waiting (CI on PR #533); red CI (e.g. missing `.allocations` of the four conformance programs) gets a fix worker from the PR state.
argus closed this issue 2026-10-27 14:19:43 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
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#136
No description provided.