From 13c4b89a90a8ddd9373dd24b2db6d3f56b7c3a34 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 31 May 2026 12:15:11 +0100 Subject: [PATCH] =?UTF-8?q?feat(migration/app/proven):=20port=20ProvenErro?= =?UTF-8?q?r.affine=20(megaport=20STEP=208=20=E2=80=94=20single-file=20fol?= =?UTF-8?q?low-up)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports src/app/proven/ProvenError.res (32 LoC) to Mode-A AffineScript. Self-contained error-types module — pure data record + 5 constructor helpers + toString. No FFI, no cross-module deps, no Tea_/Pixi/Gossamer surface. Type checks against AffineScript stdlib. Translation choices: - record-field punning `{operation}` → explicit `#{operation: operation}` - labelled args `(~name: T)` → positional `(name: T)` (AS has no labels) - template literal `` `[${a}] ${b}` `` → `"[" ++ a ++ "] " ++ b` (no JS templates) What this PR is NOT Does NOT replace src/app/proven/ProvenError.res. Consumers (SafeFloat, SafeJson, SafeAngle) still reference the .res — those ports need cross-module `use` resolution (#228 family) before they can swap to the .affine. Refs standards#279 (megaport STEP 8). Adjacent to idaptik#110 which landed the first migration/shared/ Mode-A file. --- migration/app/proven/ProvenError.affine | 59 +++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 migration/app/proven/ProvenError.affine diff --git a/migration/app/proven/ProvenError.affine b/migration/app/proven/ProvenError.affine new file mode 100644 index 00000000..fb596a85 --- /dev/null +++ b/migration/app/proven/ProvenError.affine @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (c) 2026 Joshua B. Jewell and Jonathan D.A. Jewell +// +// ProvenError.affine — error types for proven-safe modules. +// +// Translation of src/app/proven/ProvenError.res (32 LoC). Self-contained +// pure-data + pure-constructors module — no FFI, no cross-module deps, +// no Tea_/Pixi/Gossamer surface. Cleanest possible Mode-A AffineScript +// port in idaptik's src/app/ tree. +// +// Translation choices: +// `type x = { field: T, ... }` → unchanged (no trailing comma). +// `let f = (~name: T, ...): U => body` → `fn f(name: T, ...) -> U { body }` +// (AS uses positional args, not labelled — the ReScript ~prefix +// drops on the call site for `notANumber(operation, message)` etc.). +// `{operation, message, errorType}` → `#{operation: operation, ...}` +// punning shorthand drops; AS record literals are explicit. +// `` `[${a}] ${b}: ${c}` `` template-literal → `"[" ++ a ++ "] " ++ b ++ ": " ++ c` +// AS uses `++` concatenation; template literals are JS-specific. +// +// What this PR is NOT +// Does NOT replace src/app/proven/ProvenError.res in the build. The .res +// still owns the runtime contract — SafeFloat / SafeJson / SafeAngle +// reference it directly. Replacement requires the same .affine→.mjs +// codegen story tracked under standards#279 STEP 8. +// +// Refs: standards#279 (megaport step), standards#252 (campaign umbrella). + +module ProvenError; + +type ProvenError = { + operation: String, + message: String, + errorType: String, +} + +fn notANumber(operation: String, message: String) -> ProvenError { + #{ operation: operation, message: message, errorType: "NaN" } +} + +fn infinity(operation: String, message: String) -> ProvenError { + #{ operation: operation, message: message, errorType: "Infinity" } +} + +fn parseFailure(operation: String, message: String) -> ProvenError { + #{ operation: operation, message: message, errorType: "ParseFailure" } +} + +fn divisionByZero(operation: String, message: String) -> ProvenError { + #{ operation: operation, message: message, errorType: "DivisionByZero" } +} + +fn invalidArgument(operation: String, message: String) -> ProvenError { + #{ operation: operation, message: message, errorType: "InvalidArgument" } +} + +fn toString(err: ProvenError) -> String { + "[" ++ err.errorType ++ "] " ++ err.operation ++ ": " ++ err.message +}