From 61a066891329d00141e2fc8c94c5efdef24b137a Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 26 Jun 2026 19:00:05 +0000 Subject: [PATCH 1/4] WIP: Grow bash AST: EnvUnset node + multi-binding env nesting (dissolve orch_ --- dsl/extdeps/languages/bash/program.dag | 3 ++ src/v2/extdeps/languages/bash.dag | 52 +++++++++++++++++++ src/v2/workflow/orchestration_emit.dag | 25 +++++++-- src/v2/workflow/orchestration_emit_test.dag | 3 +- .../workflow/orchestration_stmt_emit_test.dag | 29 +++++++++++ src/v2/workflow/shell_emit.dag | 17 ++++++ 6 files changed, 125 insertions(+), 4 deletions(-) diff --git a/dsl/extdeps/languages/bash/program.dag b/dsl/extdeps/languages/bash/program.dag index e8d7700683a..d5c08e99176 100644 --- a/dsl/extdeps/languages/bash/program.dag +++ b/dsl/extdeps/languages/bash/program.dag @@ -39,6 +39,7 @@ type ShellStmt | Pipe { left: ShellStmt, right: ShellStmt } | EnvPrefixed { name: String, value: ShellWord, command: ShellStmt } + | EnvUnset { name: String, command: ShellStmt } | WithRedir { stmt: ShellStmt, redir: Redir } | Heredoc { path: ShellWord, delimiter: String, body: String } @@ -136,6 +137,8 @@ fn serialize_stmt(s: ShellStmt) -> String { concat(serialize_stmt(s: l), concat(" | ", serialize_stmt(s: r))) EnvPrefixed { name: n, value: v, command: c } => concat(n, concat("=", concat(serialize_word(w: v), concat(" ", serialize_stmt(s: c))))) + EnvUnset { name: n, command: c } => + concat("env -u ", concat(n, concat(" ", serialize_stmt(s: c)))) WithRedir { stmt: st, redir: rd } => concat(serialize_stmt(s: st), concat(" ", serialize_redir(r: rd))) Exit { code: c } => concat("exit ", to_string(c)) diff --git a/src/v2/extdeps/languages/bash.dag b/src/v2/extdeps/languages/bash.dag index 81b51832ee7..013493e0d5f 100644 --- a/src/v2/extdeps/languages/bash.dag +++ b/src/v2/extdeps/languages/bash.dag @@ -2011,6 +2011,58 @@ fn bash_stmt_env_prefixed_target_model(name: String, value: String, command: Str ) } +fn bash_stmt_env_unset_tokens() -> List { + [ + FixedToken { token_class: ^bash_token_env_unset_prefix }, + BoundToken { token_class: ^bash_token_orch_raw, binding: ^bash_stmt_envp_unset_name }, + FixedToken { token_class: ^bash_token_env_unset_sp }, + BoundToken { token_class: ^bash_token_orch_raw, binding: ^bash_stmt_envp_unset_command } + ] +} + +data bash_stmt_env_unset_emitted: Node = bash_conj_emitted_from_tokens( + tokens: bash_stmt_env_unset_tokens() +) + +fn bash_stmt_env_unset_source_text(name: String, command: String) -> String { + concat("env -u ", concat(name, concat(" ", command))) +} + +fn bash_stmt_env_unset_lex() -> LexRules { + phrase_to_lex_rules(p: phrase([ + span(text: "env -u ", class: ^bash_token_env_unset_prefix), + span(text: " ", class: ^bash_token_env_unset_sp) + ])) +} + +fn bash_stmt_env_unset_translation_rules_node() -> Node { + bash_relation_translation_rules_node( + rule_name: ^bash_relation_rule_stmt_env_unset, + lhs: ^bash_production_stmt_env_unset, + tokens: bash_stmt_env_unset_tokens(), + emitted: bash_stmt_env_unset_emitted + ) +} + +fn bash_stmt_env_unset_binding_spellings(name: String, command: String) -> Map { + map_insert( + map_insert(empty_map(), ^bash_stmt_envp_unset_name, name), + ^bash_stmt_envp_unset_command, command + ) +} + +fn bash_stmt_env_unset_target_model(name: String, command: String) -> TargetModel { + bash_make_bound_tokens_target_model( + rules: bash_stmt_env_unset_translation_rules_node(), + source_literal: ^bash_stmt_env_unset_source_literal, + production_name: ^bash_production_stmt_env_unset, + tokens: bash_stmt_env_unset_tokens(), + source_text: bash_stmt_env_unset_source_text(name: name, command: command), + lex: bash_stmt_env_unset_lex(), + binding_spellings: bash_stmt_env_unset_binding_spellings(name: name, command: command) + ) +} + fn bash_stmt_if_tokens() -> List { [ FixedToken { token_class: ^bash_token_if_kw }, diff --git a/src/v2/workflow/orchestration_emit.dag b/src/v2/workflow/orchestration_emit.dag index 5818f0a22af..19e87c20661 100644 --- a/src/v2/workflow/orchestration_emit.dag +++ b/src/v2/workflow/orchestration_emit.dag @@ -3,7 +3,7 @@ module v2.workflow.orchestration_emit import v2.compiler.emit { emit } import v2.compiler.infer { InferredFacts, InferredTree } import v2.workflow.shell_emit { emit_shell_stmt } -import extdeps.languages.bash.program { RawLine } +import extdeps.languages.bash.program { RawLine, ShellStmt, EnvPrefixed, EnvUnset, Lit } import extdeps.communication.medium { Medium } import v2.extdeps.languages.bash { orch_run_emitted_command, @@ -20,7 +20,8 @@ import v2.std.orchestration { Pipeline, EscalationLevel, LogMatches, - EnvBinding + EnvBinding, + EnvSet } import v2.std.algebra { FreeMonoid, list_head, list_tail, HeadFound, HeadAbsent, TailFound, TailAbsent } import v2.std.collection { List, Map, Optional, Present, Absent } @@ -50,7 +51,25 @@ fn orch_emit_facts_lookup(key: Node) -> Witness { } } -data orch_run_env_reduction_dissolution_trigger: String = "orchestration_emit Run/Step/Retry path reduces onto emit_shell_stmt: an env-FREE Run lowers to a RawLine carrying the command and is delegated to emit_shell_stmt now (single orch_raw, green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). An env-BEARING Run lowers to an EnvPrefixed over env plus a RawLine command, which is a multi-orch_raw construct hitting the same emit-kernel String-to-List-Int-codepoint straddle as the held welds, so it stays on the orch_run_emitted_command single-string render (orch_emit_run_env_welded) until that debt clears. DISSOLVES WHEN the emit-kernel multi-orch_raw straddle for EnvPrefixed is fixed (same debt as bash_multi_orch_raw_welds_dissolution_trigger; debt surfaced to operator 2026-06-26)." +data orch_run_env_reduction_dissolution_trigger: String = "orchestration_emit Run/Step/Retry path reduces onto emit_shell_stmt: an env-FREE Run lowers to a RawLine carrying the command and is delegated to emit_shell_stmt now (single orch_raw, green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). An env-BEARING Run lowers via lower_env_bindings to a nested EnvPrefixed/EnvUnset tree over the Run.env FreeMonoid with a RawLine command at the leaf, then delegates to emit_shell_stmt. The bash AST now models EnvUnset (env -u NAME) and multi-binding via nesting, proven byte-identical by stmt_env_unset_byte_identical_holds and stmt_env_multi_binding_byte_identical_holds. orch_emit_run_env_welded DISSOLVES WHEN #5841 (String-grounding, emit-kernel straddle fix) lands and the orch_emit_run integration is wired: replace orch_emit_run_env_welded call with emit_shell_stmt(lower_env_bindings(env: r.env, command: RawLine { text: r.command })) and delete the weld scaffold (deletion-is-receipt). Verify by orch_run_multi_binding_env_emits_correctly (multi EnvSet + EnvUnset oracle) going green-by-execution post-#5841." + +fn lower_env_bindings(env: FreeMonoid, command: ShellStmt) -> ShellStmt { + match list_head(xs: env) { + HeadAbsent => command + HeadFound { value: b } => + match list_tail(xs: env) { + TailAbsent => match b { + EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: command } + EnvUnset { name: n } => EnvUnset { name: n, command: command } + } + TailFound { rest: rest } => + match b { + EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: lower_env_bindings(env: rest, command: command) } + EnvUnset { name: n } => EnvUnset { name: n, command: lower_env_bindings(env: rest, command: command) } + } + } + } +} fn orch_emit_run(r: Run) -> Outcome> { match list_head(xs: r.env) { diff --git a/src/v2/workflow/orchestration_emit_test.dag b/src/v2/workflow/orchestration_emit_test.dag index 969a55560c5..27a86bf1b5e 100644 --- a/src/v2/workflow/orchestration_emit_test.dag +++ b/src/v2/workflow/orchestration_emit_test.dag @@ -91,6 +91,7 @@ test fn orch_run_empty_env_delegates_to_shell_emit_holds() -> Bool { test fn orch_run_env_reduction_trigger_recorded_holds() -> Bool { string_contains(s: orch_run_env_reduction_dissolution_trigger, pattern: "EnvPrefixed") - && string_contains(s: orch_run_env_reduction_dissolution_trigger, pattern: "straddle") + && string_contains(s: orch_run_env_reduction_dissolution_trigger, pattern: "EnvUnset") + && string_contains(s: orch_run_env_reduction_dissolution_trigger, pattern: "lower_env_bindings") && string_contains(s: orch_run_env_reduction_dissolution_trigger, pattern: "DISSOLVES WHEN") } diff --git a/src/v2/workflow/orchestration_stmt_emit_test.dag b/src/v2/workflow/orchestration_stmt_emit_test.dag index 63495303905..742ad23de94 100644 --- a/src/v2/workflow/orchestration_stmt_emit_test.dag +++ b/src/v2/workflow/orchestration_stmt_emit_test.dag @@ -12,6 +12,7 @@ import extdeps.languages.bash.program { AndOr, Pipe, EnvPrefixed, + EnvUnset, WithRedir, Heredoc, AndThen, @@ -157,6 +158,34 @@ test fn stmt_env_prefixed_has_teeth_holds() -> Bool { stmt_differs_from_oracle_of(s: envp_t(), other: EnvPrefixed { name: "TMPDIR", value: Lit { text: "/x" }, command: cmd_true() }) } +fn env_unset_t() -> ShellStmt { + EnvUnset { name: "TMPDIR", command: cmd_true() } +} + +test fn stmt_env_unset_byte_identical_holds() -> Bool { + stmt_emits_oracle(s: env_unset_t()) +} + +test fn stmt_env_unset_has_teeth_holds() -> Bool { + stmt_differs_from_oracle_of(s: env_unset_t(), other: EnvUnset { name: "OTHER", command: cmd_true() }) +} + +fn env_multi_binding_t() -> ShellStmt { + EnvPrefixed { + name: "KEY", + value: Lit { text: "val" }, + command: EnvUnset { name: "TMPDIR", command: cmd_true() } + } +} + +test fn stmt_env_multi_binding_byte_identical_holds() -> Bool { + stmt_emits_oracle(s: env_multi_binding_t()) +} + +test fn stmt_env_multi_binding_has_teeth_holds() -> Bool { + stmt_differs_from_oracle_of(s: env_multi_binding_t(), other: EnvPrefixed { name: "KEY", value: Lit { text: "other" }, command: EnvUnset { name: "TMPDIR", command: cmd_true() } }) +} + fn heredoc_t() -> ShellStmt { Heredoc { path: Lit { text: "out" }, delimiter: "EOF", body: "hello" } } diff --git a/src/v2/workflow/shell_emit.dag b/src/v2/workflow/shell_emit.dag index 6ff9fa67c1a..31859ff8e41 100644 --- a/src/v2/workflow/shell_emit.dag +++ b/src/v2/workflow/shell_emit.dag @@ -23,6 +23,8 @@ import v2.extdeps.languages.bash { bash_stmt_with_redir_target_model, bash_stmt_env_prefixed_emitted, bash_stmt_env_prefixed_target_model, + bash_stmt_env_unset_emitted, + bash_stmt_env_unset_target_model, bash_stmt_if_emitted, bash_stmt_if_target_model, bash_stmt_heredoc_emitted, @@ -50,6 +52,7 @@ import extdeps.languages.bash.program { AndOr, Pipe, EnvPrefixed, + EnvUnset, WithRedir, Heredoc, Exit, @@ -220,6 +223,16 @@ fn emit_stmt_env_prefixed(name: String, value: String, command: String) -> Outco ) } +fn emit_stmt_env_unset(name: String, command: String) -> Outcome> { + emit( + tree: InferredTree { + root: bash_stmt_env_unset_emitted, + facts: Map { lookup: shell_emit_facts_lookup } + }, + target: bash_stmt_env_unset_target_model(name: name, command: command) + ) +} + fn emit_stmt_if(cond: String, body: String) -> Outcome> { emit( tree: InferredTree { @@ -390,6 +403,10 @@ fn emit_shell_stmt(s: ShellStmt) -> Outcome> { emit_stmt_env_prefixed(name: n, value: mv.carried, command: mc.carried) }) }) + EnvUnset { name: n, command: c } => + bind_outcome(o: emit_shell_stmt(s: c), f: fn(mc) { + emit_stmt_env_unset(name: n, command: mc.carried) + }) WithRedir { stmt: st, redir: rd } => bind_outcome(o: emit_shell_stmt(s: st), f: fn(mst) { bind_outcome(o: emit_redir(r: rd), f: fn(mr) { From 84b12242682004c4f2877d9d6f1619938401aad6 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 26 Jun 2026 19:12:14 +0000 Subject: [PATCH 2/4] WIP: Grow bash AST: EnvUnset node + multi-binding env nesting (dissolve orch_ --- dsl/extdeps/languages/bash/program.dag | 4 ++-- src/v2/workflow/orchestration_emit.dag | 21 ++++++++++--------- .../workflow/orchestration_stmt_emit_test.dag | 8 +++---- src/v2/workflow/shell_emit.dag | 4 ++-- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/dsl/extdeps/languages/bash/program.dag b/dsl/extdeps/languages/bash/program.dag index d5c08e99176..5a48cf15014 100644 --- a/dsl/extdeps/languages/bash/program.dag +++ b/dsl/extdeps/languages/bash/program.dag @@ -39,7 +39,7 @@ type ShellStmt | Pipe { left: ShellStmt, right: ShellStmt } | EnvPrefixed { name: String, value: ShellWord, command: ShellStmt } - | EnvUnset { name: String, command: ShellStmt } + | EnvUnsetCmd { name: String, command: ShellStmt } | WithRedir { stmt: ShellStmt, redir: Redir } | Heredoc { path: ShellWord, delimiter: String, body: String } @@ -137,7 +137,7 @@ fn serialize_stmt(s: ShellStmt) -> String { concat(serialize_stmt(s: l), concat(" | ", serialize_stmt(s: r))) EnvPrefixed { name: n, value: v, command: c } => concat(n, concat("=", concat(serialize_word(w: v), concat(" ", serialize_stmt(s: c))))) - EnvUnset { name: n, command: c } => + EnvUnsetCmd { name: n, command: c } => concat("env -u ", concat(n, concat(" ", serialize_stmt(s: c)))) WithRedir { stmt: st, redir: rd } => concat(serialize_stmt(s: st), concat(" ", serialize_redir(r: rd))) diff --git a/src/v2/workflow/orchestration_emit.dag b/src/v2/workflow/orchestration_emit.dag index 19e87c20661..550ab9644e1 100644 --- a/src/v2/workflow/orchestration_emit.dag +++ b/src/v2/workflow/orchestration_emit.dag @@ -3,7 +3,7 @@ module v2.workflow.orchestration_emit import v2.compiler.emit { emit } import v2.compiler.infer { InferredFacts, InferredTree } import v2.workflow.shell_emit { emit_shell_stmt } -import extdeps.languages.bash.program { RawLine, ShellStmt, EnvPrefixed, EnvUnset, Lit } +import extdeps.languages.bash.program { RawLine, ShellStmt, EnvPrefixed, EnvUnsetCmd, Lit } import extdeps.communication.medium { Medium } import v2.extdeps.languages.bash { orch_run_emitted_command, @@ -53,20 +53,21 @@ fn orch_emit_facts_lookup(key: Node) -> Witness { data orch_run_env_reduction_dissolution_trigger: String = "orchestration_emit Run/Step/Retry path reduces onto emit_shell_stmt: an env-FREE Run lowers to a RawLine carrying the command and is delegated to emit_shell_stmt now (single orch_raw, green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). An env-BEARING Run lowers via lower_env_bindings to a nested EnvPrefixed/EnvUnset tree over the Run.env FreeMonoid with a RawLine command at the leaf, then delegates to emit_shell_stmt. The bash AST now models EnvUnset (env -u NAME) and multi-binding via nesting, proven byte-identical by stmt_env_unset_byte_identical_holds and stmt_env_multi_binding_byte_identical_holds. orch_emit_run_env_welded DISSOLVES WHEN #5841 (String-grounding, emit-kernel straddle fix) lands and the orch_emit_run integration is wired: replace orch_emit_run_env_welded call with emit_shell_stmt(lower_env_bindings(env: r.env, command: RawLine { text: r.command })) and delete the weld scaffold (deletion-is-receipt). Verify by orch_run_multi_binding_env_emits_correctly (multi EnvSet + EnvUnset oracle) going green-by-execution post-#5841." +fn lower_env_binding(b: EnvBinding, inner: ShellStmt) -> ShellStmt { + match b { + EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: inner } + EnvUnset { name: n } => EnvUnsetCmd { name: n, command: inner } + } +} + fn lower_env_bindings(env: FreeMonoid, command: ShellStmt) -> ShellStmt { match list_head(xs: env) { HeadAbsent => command HeadFound { value: b } => match list_tail(xs: env) { - TailAbsent => match b { - EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: command } - EnvUnset { name: n } => EnvUnset { name: n, command: command } - } - TailFound { rest: rest } => - match b { - EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: lower_env_bindings(env: rest, command: command) } - EnvUnset { name: n } => EnvUnset { name: n, command: lower_env_bindings(env: rest, command: command) } - } + TailAbsent => lower_env_binding(b: b, inner: command) + TailFound { tail: rest } => + lower_env_binding(b: b, inner: lower_env_bindings(env: rest, command: command)) } } } diff --git a/src/v2/workflow/orchestration_stmt_emit_test.dag b/src/v2/workflow/orchestration_stmt_emit_test.dag index 742ad23de94..9d165d351ef 100644 --- a/src/v2/workflow/orchestration_stmt_emit_test.dag +++ b/src/v2/workflow/orchestration_stmt_emit_test.dag @@ -12,7 +12,7 @@ import extdeps.languages.bash.program { AndOr, Pipe, EnvPrefixed, - EnvUnset, + EnvUnsetCmd, WithRedir, Heredoc, AndThen, @@ -159,7 +159,7 @@ test fn stmt_env_prefixed_has_teeth_holds() -> Bool { } fn env_unset_t() -> ShellStmt { - EnvUnset { name: "TMPDIR", command: cmd_true() } + EnvUnsetCmd { name: "TMPDIR", command: cmd_true() } } test fn stmt_env_unset_byte_identical_holds() -> Bool { @@ -167,14 +167,14 @@ test fn stmt_env_unset_byte_identical_holds() -> Bool { } test fn stmt_env_unset_has_teeth_holds() -> Bool { - stmt_differs_from_oracle_of(s: env_unset_t(), other: EnvUnset { name: "OTHER", command: cmd_true() }) + stmt_differs_from_oracle_of(s: env_unset_t(), other: EnvUnsetCmd { name: "OTHER", command: cmd_true() }) } fn env_multi_binding_t() -> ShellStmt { EnvPrefixed { name: "KEY", value: Lit { text: "val" }, - command: EnvUnset { name: "TMPDIR", command: cmd_true() } + command: EnvUnsetCmd { name: "TMPDIR", command: cmd_true() } } } diff --git a/src/v2/workflow/shell_emit.dag b/src/v2/workflow/shell_emit.dag index 31859ff8e41..b3120de62f2 100644 --- a/src/v2/workflow/shell_emit.dag +++ b/src/v2/workflow/shell_emit.dag @@ -52,7 +52,7 @@ import extdeps.languages.bash.program { AndOr, Pipe, EnvPrefixed, - EnvUnset, + EnvUnsetCmd, WithRedir, Heredoc, Exit, @@ -403,7 +403,7 @@ fn emit_shell_stmt(s: ShellStmt) -> Outcome> { emit_stmt_env_prefixed(name: n, value: mv.carried, command: mc.carried) }) }) - EnvUnset { name: n, command: c } => + EnvUnsetCmd { name: n, command: c } => bind_outcome(o: emit_shell_stmt(s: c), f: fn(mc) { emit_stmt_env_unset(name: n, command: mc.carried) }) From 63c111bbcbcc7054d46cfc5866db1e2d019ad014 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 26 Jun 2026 19:22:36 +0000 Subject: [PATCH 3/4] Fix EnvUnsetCmd naming (avoid EnvUnset variant collision), move lower_env_bindings to bridge module Co-Authored-By: Claude Sonnet 4.6 --- src/v2/workflow/orch_env_lower.dag | 24 ++++++++++++++++++ src/v2/workflow/orchestration_emit.dag | 25 +++---------------- .../workflow/orchestration_stmt_emit_test.dag | 2 +- 3 files changed, 28 insertions(+), 23 deletions(-) create mode 100644 src/v2/workflow/orch_env_lower.dag diff --git a/src/v2/workflow/orch_env_lower.dag b/src/v2/workflow/orch_env_lower.dag new file mode 100644 index 00000000000..e1cea8e0a5e --- /dev/null +++ b/src/v2/workflow/orch_env_lower.dag @@ -0,0 +1,24 @@ +module v2.workflow.orch_env_lower + +import v2.std.orchestration { EnvBinding, EnvSet, EnvUnset } +import v2.std.algebra { FreeMonoid, list_head, list_tail, HeadFound, HeadAbsent, TailFound, TailAbsent } +import extdeps.languages.bash.program { ShellStmt, EnvPrefixed, EnvUnsetCmd, Lit } + +fn lower_env_binding(b: EnvBinding, inner: ShellStmt) -> ShellStmt { + match b { + EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: inner } + EnvUnset { name: n } => EnvUnsetCmd { name: n, command: inner } + } +} + +fn lower_env_bindings(env: FreeMonoid, command: ShellStmt) -> ShellStmt { + match list_head(xs: env) { + HeadAbsent => command + HeadFound { value: b } => + match list_tail(xs: env) { + TailAbsent => lower_env_binding(b: b, inner: command) + TailFound { tail: rest } => + lower_env_binding(b: b, inner: lower_env_bindings(env: rest, command: command)) + } + } +} diff --git a/src/v2/workflow/orchestration_emit.dag b/src/v2/workflow/orchestration_emit.dag index 550ab9644e1..233c395680e 100644 --- a/src/v2/workflow/orchestration_emit.dag +++ b/src/v2/workflow/orchestration_emit.dag @@ -3,7 +3,8 @@ module v2.workflow.orchestration_emit import v2.compiler.emit { emit } import v2.compiler.infer { InferredFacts, InferredTree } import v2.workflow.shell_emit { emit_shell_stmt } -import extdeps.languages.bash.program { RawLine, ShellStmt, EnvPrefixed, EnvUnsetCmd, Lit } +import extdeps.languages.bash.program { RawLine } +import v2.workflow.orch_env_lower { lower_env_bindings } import extdeps.communication.medium { Medium } import v2.extdeps.languages.bash { orch_run_emitted_command, @@ -20,8 +21,7 @@ import v2.std.orchestration { Pipeline, EscalationLevel, LogMatches, - EnvBinding, - EnvSet + EnvBinding } import v2.std.algebra { FreeMonoid, list_head, list_tail, HeadFound, HeadAbsent, TailFound, TailAbsent } import v2.std.collection { List, Map, Optional, Present, Absent } @@ -53,25 +53,6 @@ fn orch_emit_facts_lookup(key: Node) -> Witness { data orch_run_env_reduction_dissolution_trigger: String = "orchestration_emit Run/Step/Retry path reduces onto emit_shell_stmt: an env-FREE Run lowers to a RawLine carrying the command and is delegated to emit_shell_stmt now (single orch_raw, green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). An env-BEARING Run lowers via lower_env_bindings to a nested EnvPrefixed/EnvUnset tree over the Run.env FreeMonoid with a RawLine command at the leaf, then delegates to emit_shell_stmt. The bash AST now models EnvUnset (env -u NAME) and multi-binding via nesting, proven byte-identical by stmt_env_unset_byte_identical_holds and stmt_env_multi_binding_byte_identical_holds. orch_emit_run_env_welded DISSOLVES WHEN #5841 (String-grounding, emit-kernel straddle fix) lands and the orch_emit_run integration is wired: replace orch_emit_run_env_welded call with emit_shell_stmt(lower_env_bindings(env: r.env, command: RawLine { text: r.command })) and delete the weld scaffold (deletion-is-receipt). Verify by orch_run_multi_binding_env_emits_correctly (multi EnvSet + EnvUnset oracle) going green-by-execution post-#5841." -fn lower_env_binding(b: EnvBinding, inner: ShellStmt) -> ShellStmt { - match b { - EnvSet { name: n, value: v } => EnvPrefixed { name: n, value: Lit { text: v }, command: inner } - EnvUnset { name: n } => EnvUnsetCmd { name: n, command: inner } - } -} - -fn lower_env_bindings(env: FreeMonoid, command: ShellStmt) -> ShellStmt { - match list_head(xs: env) { - HeadAbsent => command - HeadFound { value: b } => - match list_tail(xs: env) { - TailAbsent => lower_env_binding(b: b, inner: command) - TailFound { tail: rest } => - lower_env_binding(b: b, inner: lower_env_bindings(env: rest, command: command)) - } - } -} - fn orch_emit_run(r: Run) -> Outcome> { match list_head(xs: r.env) { HeadAbsent => emit_shell_stmt(s: RawLine { text: r.command }) diff --git a/src/v2/workflow/orchestration_stmt_emit_test.dag b/src/v2/workflow/orchestration_stmt_emit_test.dag index 9d165d351ef..1cb90834caa 100644 --- a/src/v2/workflow/orchestration_stmt_emit_test.dag +++ b/src/v2/workflow/orchestration_stmt_emit_test.dag @@ -183,7 +183,7 @@ test fn stmt_env_multi_binding_byte_identical_holds() -> Bool { } test fn stmt_env_multi_binding_has_teeth_holds() -> Bool { - stmt_differs_from_oracle_of(s: env_multi_binding_t(), other: EnvPrefixed { name: "KEY", value: Lit { text: "other" }, command: EnvUnset { name: "TMPDIR", command: cmd_true() } }) + stmt_differs_from_oracle_of(s: env_multi_binding_t(), other: EnvPrefixed { name: "KEY", value: Lit { text: "other" }, command: EnvUnsetCmd { name: "TMPDIR", command: cmd_true() } }) } fn heredoc_t() -> ShellStmt { From f409b2ff9695b147286da55528258f95eff6cf8b Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sat, 27 Jun 2026 02:26:42 +0000 Subject: [PATCH 4/4] Fix dissolution trigger: restore DISSOLVES WHEN phrase for trigger witness Co-Authored-By: Claude Sonnet 4.6 --- src/v2/workflow/orchestration_emit.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v2/workflow/orchestration_emit.dag b/src/v2/workflow/orchestration_emit.dag index 203c5c38af7..8ec8a083acb 100644 --- a/src/v2/workflow/orchestration_emit.dag +++ b/src/v2/workflow/orchestration_emit.dag @@ -51,7 +51,7 @@ fn orch_emit_facts_lookup(key: Node) -> Witness { } } -data orch_run_env_reduction_dissolution_trigger: String = "orchestration_emit Run/Step/Retry path reduces onto emit_shell_stmt: an env-FREE Run lowers to a RawLine carrying the command and is delegated to emit_shell_stmt now (single orch_raw, green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). An env-BEARING Run lowers via lower_env_bindings (orch_env_lower.dag) to a nested EnvPrefixed/EnvUnsetCmd tree over the Run.env FreeMonoid with a RawLine command at the leaf, then delegates to emit_shell_stmt. BOTH blockers are now cleared: (1) the emit-kernel String<->List-Int-codepoint straddle is FIXED by #5841 (free_monoid_to_string grounding; program_multi_orch_raw_byte_identical_holds green-by-execution); (2) the bash AST now models EnvUnsetCmd (env -u NAME) and multi-binding via nesting, proven byte-identical by stmt_env_unset_byte_identical_holds and stmt_env_multi_binding_byte_identical_holds (#5846). orch_emit_run_env_welded DISSOLVES in the integration follow-on: replace the orch_emit_run_env_welded call with emit_shell_stmt(lower_env_bindings(env: r.env, command: RawLine { text: r.command })) and delete the weld scaffold (deletion-is-receipt). Verify by orch_run_multi_binding_env_emits_correctly (multi EnvSet + EnvUnset oracle) going green-by-execution." +data orch_run_env_reduction_dissolution_trigger: String = "orchestration_emit Run/Step/Retry path reduces onto emit_shell_stmt: an env-FREE Run lowers to a RawLine carrying the command and is delegated to emit_shell_stmt now (single orch_raw, green path, proven byte-identical by orch_run_empty_env_delegates_to_shell_emit). An env-BEARING Run lowers via lower_env_bindings (orch_env_lower.dag) to a nested EnvPrefixed/EnvUnsetCmd tree over the Run.env FreeMonoid with a RawLine command at the leaf, then delegates to emit_shell_stmt. BOTH blockers are now cleared: (1) the emit-kernel String<->List-Int-codepoint straddle is FIXED by #5841 (free_monoid_to_string grounding; program_multi_orch_raw_byte_identical_holds green-by-execution); (2) the bash AST now models EnvUnsetCmd (env -u NAME) and multi-binding via nesting, proven byte-identical by stmt_env_unset_byte_identical_holds and stmt_env_multi_binding_byte_identical_holds (#5846). orch_emit_run_env_welded DISSOLVES WHEN the integration follow-on lands: replace the orch_emit_run_env_welded call with emit_shell_stmt(lower_env_bindings(env: r.env, command: RawLine { text: r.command })) and delete the weld scaffold (deletion-is-receipt). Verify by orch_run_multi_binding_env_emits_correctly (multi EnvSet + EnvUnset oracle) going green-by-execution." fn orch_emit_run(r: Run) -> Outcome> { match list_head(xs: r.env) {