From 76aa5cf68ed4f851983d2936f4a3ea150759aea6 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 19 May 2026 04:17:22 +0000 Subject: [PATCH 1/2] =?UTF-8?q?v4=20T-4.5:=20bind=20OS-1=20process/file=5F?= =?UTF-8?q?system=20refinement=20scaffolds=20to=20concrete=20T-25-core=20t?= =?UTF-8?q?argets=20(yellow=20surface=E2=86=92dissolve=20loop;=20no=20.dag?= =?UTF-8?q?=20fact-bundle=20expansion,=20no=20#3280=20fold)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refines the OS-1 Refinement Scaffold Disposition ledger so each of the seven YELLOW T-4.5 scaffolds names its concrete T-25-core target shape (ProcessId/SignalNum→PositiveInt, ExitCode→NonNegativeInt, the four PosixByteString byte-records→non-empty NUL-free refinement) plus an explicit surface→dissolve loop, per the operator yellow-discipline that a tracked yellow must bind to a concrete plan rather than sit as an indefinite tracked comment. Decision-record only: OS-1 designates DECISIONS.md as the home for these scaffold dispositions; .dag source keeps its terse tags unchanged. No fact-bundle expansion (T-25-core substrate not landed — bound, not dissolved), no #3280 freeze fold. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/v4/DECISIONS.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/v4/DECISIONS.md b/src/v4/DECISIONS.md index 3f3595f7496..6847fbdab4c 100644 --- a/src/v4/DECISIONS.md +++ b/src/v4/DECISIONS.md @@ -403,6 +403,44 @@ carriers: `ProcessId = Int`, `ExitCode = Int`, `SignalNum = Int`, them now would be fact-bundle-rework-class work, outside the NOT-D2-held de-prose scope. +Each scaffold is bound to a concrete T-25-core target shape and a +surface→dissolve loop (operator yellow-discipline 2026-05-18: a tracked +yellow names its primitive, lands the substrate, and dissolves on landing +— never an indefinite tracked comment). T-25-core models a refinement as +a **base carrier + a named fail-closed validation discharged at the +constructor boundary** (`TASKS.md` T-25 / `docs/coercion-design.md` +Category 6); the substrate is **not yet landed** (`std/collection.dag` +carries the `non_empty` predicate but no refined carrier; `integer.dag` +states "no `where`-clause"), so these stay bound-not-dissolved: + +- `ProcessId = Int` → T-25-core `PositiveInt` (POSIX `pid_t` of a real + process is `> 0`; `0`/`-1` are sentinel/group, not a process id). + Dissolve: replace the bare `Int` alias with the `> 0` + constructor-validated refinement. +- `SignalNum = Int` → T-25-core `PositiveInt` (a delivered/terminating + signal number is `>= 1`; `0` is the null signal, not a termination + fact). Dissolve: same shape as `ProcessId`. +- `ExitCode = Int` → T-25-core `NonNegativeInt` (POSIX `WEXITSTATUS` is + `0..255`; non-negative is the minimal floor, the `0..255` bound is the + fuller fact deferred with it). Dissolve: replace with the non-negative + constructor-validated refinement. +- `NamedPathComponent`, `PosixArgument`, `PosixEnvironmentName`, + `PosixEnvironmentValue` (each `{ bytes: PosixByteString }`) → T-25-core + non-empty NUL-free `PosixByteString` refinement (POSIX pathname + components and `exec` argument/environment strings are non-empty byte + strings containing no NUL; `PosixEnvironmentName` additionally excludes + `=`). Dissolve: replace the bare byte-record with the + constructor-validated byte-string refinement carrying that predicate. + +The surface→dissolve loop for all seven: name the T-25-core primitive +(above) → land the T-25-core `std/` substrate PR → dissolve each scaffold +in the same change that consumes it, replacing the bare alias/byte-record +with the constructor-validated refinement; trigger stays **T-25-core / +T-30 fact-density gate**. `.dag` source keeps only the terse +`scaffold: … ; trigger T-25-core/T-30.` tags (OS-1 row: ledgers are +decision records, not source comments) — this binding lives here, not in +the `.dag` files, and is not a `.dag` fact-bundle expansion. + ## Part 2 — RATIFIED 2026-05-15 (cascade-closures — now in Part 1) > **All three (U2, C3, C1) were ratified and are encoded — see Part 1.** From 606f6313821c7875a1a48c36242c15df519a6601 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Tue, 19 May 2026 04:26:17 +0000 Subject: [PATCH 2/2] =?UTF-8?q?v4=20T-4.5:=20fix=20OS-1=20byte-record=20bi?= =?UTF-8?q?nding=20=E2=80=94=20non-empty=20is=20per-carrier,=20not=20share?= =?UTF-8?q?d=20(POSIX=20permits=20empty=20argv=20elements=20/=20env=20valu?= =?UTF-8?q?es)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses blocking review: binding PosixArgument and PosixEnvironmentValue to a non-empty refinement made valid POSIX exec/env states (empty argv[i], FOO=) unrepresentable. The shared fact across the four byte-records is NUL-free (NUL-terminated C strings); non-empty applies only to NamedPathComponent (also excludes /) and PosixEnvironmentName (also excludes =). PosixArgument / PosixEnvironmentValue are NUL-free only. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/v4/DECISIONS.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/v4/DECISIONS.md b/src/v4/DECISIONS.md index 6847fbdab4c..465e776571c 100644 --- a/src/v4/DECISIONS.md +++ b/src/v4/DECISIONS.md @@ -424,13 +424,26 @@ states "no `where`-clause"), so these stay bound-not-dissolved: `0..255`; non-negative is the minimal floor, the `0..255` bound is the fuller fact deferred with it). Dissolve: replace with the non-negative constructor-validated refinement. -- `NamedPathComponent`, `PosixArgument`, `PosixEnvironmentName`, - `PosixEnvironmentValue` (each `{ bytes: PosixByteString }`) → T-25-core - non-empty NUL-free `PosixByteString` refinement (POSIX pathname - components and `exec` argument/environment strings are non-empty byte - strings containing no NUL; `PosixEnvironmentName` additionally excludes - `=`). Dissolve: replace the bare byte-record with the - constructor-validated byte-string refinement carrying that predicate. +- The four `{ bytes: PosixByteString }` byte-records → T-25-core + `PosixByteString` refinements. The shared fact is **NUL-free** (each is + a NUL-terminated C string at the `exec`/`environ`/path boundary, so an + embedded NUL is unrepresentable); the non-empty fact is **per-carrier, + not shared** — POSIX permits empty `argv` elements and empty + environment values, so non-empty must not be imposed on those: + - `NamedPathComponent` → non-empty, NUL-free, and excludes `/` (a + pathname component lies between separators; empty or `/`-bearing is + not a component). + - `PosixEnvironmentName` → non-empty, NUL-free, and excludes `=` (the + `name=value` separator); an empty name is not a valid `environ` + entry. + - `PosixArgument` → NUL-free only. An `exec` argument **may be empty** + (`argv[i] == ""`, including a deliberately empty `argv[0]`); + requiring non-empty would make valid external states unrepresentable. + - `PosixEnvironmentValue` → NUL-free only. An environment value **may + be empty** (`FOO=`); requiring non-empty would make valid external + states unrepresentable. + Dissolve: replace each bare byte-record with the constructor-validated + byte-string refinement carrying its own predicate above. The surface→dissolve loop for all seven: name the T-25-core primitive (above) → land the T-25-core `std/` substrate PR → dissolve each scaffold