From 36be6bf44b6f8e5a07d8fcf83b989c50ab264c0a Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 18 May 2026 17:57:20 +0000 Subject: [PATCH] =?UTF-8?q?fed-prims:=20Phase=20G=20=E2=80=94=20file-list-?= =?UTF-8?q?dir=20(Sys.readdir,=20sorted,=20native-safe)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 (1M context) --- hosts/ocaml/bin/run_tests.ml | 27 +++++++++++++++++++++++++++ hosts/ocaml/lib/sx_primitives.ml | 15 +++++++++++++++ plans/fed-sx-host-primitives.md | 8 +++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/hosts/ocaml/bin/run_tests.ml b/hosts/ocaml/bin/run_tests.ml index d7a57b58..cde0b3dc 100644 --- a/hosts/ocaml/bin/run_tests.ml +++ b/hosts/ocaml/bin/run_tests.ml @@ -1486,6 +1486,33 @@ let run_foundation_tests () = assert_eq "rsa non-string args" (Bool false) (call "rsa-sha256-verify" [Integer 1; Integer 2; Integer 3]); + Printf.printf "\nSuite: file-list-dir\n"; + let expect_err nm f = + (try ignore (f ()); + incr fail_count; Printf.printf " FAIL: %s — no error\n" nm + with Eval_error _ -> + incr pass_count; Printf.printf " PASS: %s\n" nm + | _ -> + incr fail_count; Printf.printf " FAIL: %s — wrong exn\n" nm) + in + let tmp = Filename.temp_file "fld" "" in + Sys.remove tmp; Unix.mkdir tmp 0o755; + let touch n = let oc = open_out (Filename.concat tmp n) in close_out oc in + touch "b.txt"; touch "a.txt"; touch "c.txt"; + assert_eq "file-list-dir sorted" + (List [String "a.txt"; String "b.txt"; String "c.txt"]) + (call "file-list-dir" [String tmp]); + expect_err "file-list-dir missing" + (fun () -> call "file-list-dir" [String (Filename.concat tmp "nope")]); + expect_err "file-list-dir not-a-dir" + (fun () -> call "file-list-dir" [String (Filename.concat tmp "a.txt")]); + expect_err "file-list-dir arity" + (fun () -> call "file-list-dir" []); + (* best-effort cleanup *) + (try List.iter (fun n -> Sys.remove (Filename.concat tmp n)) + ["a.txt"; "b.txt"; "c.txt"]; Unix.rmdir tmp + with _ -> ()); + Printf.printf "\nSuite: vm-extension-dispatch\n"; let make_bc op = ({ vc_arity = 0; vc_rest_arity = -1; vc_locals = 0; diff --git a/hosts/ocaml/lib/sx_primitives.ml b/hosts/ocaml/lib/sx_primitives.ml index 2eaea0d9..3209b744 100644 --- a/hosts/ocaml/lib/sx_primitives.ml +++ b/hosts/ocaml/lib/sx_primitives.ml @@ -3237,6 +3237,21 @@ let () = with Sys_error msg -> raise (Eval_error ("file-read: " ^ msg))) | _ -> raise (Eval_error "file-read: (path)")); + (* fed-sx Step 3 segment replay. Sorted names, no "."/".." ; + errors prefixed like file-read (msg carries enoent/enotdir). *) + register "file-list-dir" (fun args -> + match args with + | [String path] -> + (try + let names = Sys.readdir path in + let names = + Array.to_list names + |> List.filter (fun n -> n <> "." && n <> "..") in + let names = List.sort compare names in + List (List.map (fun n -> String n) names) + with Sys_error msg -> raise (Eval_error ("file-list-dir: " ^ msg))) + | _ -> raise (Eval_error "file-list-dir: (path)")); + register "file-write" (fun args -> match args with | [String path; String content] -> diff --git a/plans/fed-sx-host-primitives.md b/plans/fed-sx-host-primitives.md index 6e912649..47c02601 100644 --- a/plans/fed-sx-host-primitives.md +++ b/plans/fed-sx-host-primitives.md @@ -125,7 +125,7 @@ check** → tests → commit → tick box → Progress-log line → push. Step 2 (rsa-sha256-2018 sig-suite). **Lower priority** than E — Ed25519 is the modern default; RSA can land after the HTTP phase if time-boxed. -### Phase G — `file-list-dir`, native-safe +### Phase G — `file-list-dir`, native-safe ✅ DONE - `Sys.readdir` → sorted SX list of names (no `.`/`..`). Errors → `enoent`/ `enotdir` classified like the existing `file-read` error mapping. - Tests: list a known dir, missing dir → error, file-not-dir → error. @@ -205,6 +205,12 @@ printf '(epoch 1)\n(crypto-sha256 "abc")\n' | \ _Newest first._ +- 2026-05-18 — Phase G: `file-list-dir` primitive in + `lib/sx_primitives.ml` (Sys.readdir → sorted names, no "."/".."; + Sys_error prefixed like file-read, msg carries enoent/enotdir). + 4 tests: sorted listing, missing dir, not-a-dir, arity. WASM boot + green (Sys.readdir stubbed there); Erlang 530/530; run_tests +4. + Satisfies fed-sx Step 3 segment replay. - 2026-05-18 — Phase F: pure-OCaml `lib/sx_rsa.ml` (self-contained bignum modexp, minimal DER SPKI reader, RFC 8017 §8.2.2 PKCS#1 v1.5 verify with SHA-256 DigestInfo prefix). Primitive