Repository navigation
EffectPlan bash materializer: If, Let and Call arms materialize (for gunbc-private#60) - #11357
Conversation
…c-private#60 trigger) v2.workflow.effect_plan_bash_materialize lowers If, Let and Call through the grammar rows the Do arm already uses (assign, command, test bracket, if, new builder-only if-else tag bound to bash_orch_if's if-else target model) and serializes through the one serializer. For, While and Retry keep refusing. Every interpolated value is a single-quoted lit word; names must satisfy the POSIX name rule, now homed as posix_name_ok in extdeps.posix.shell_command_language (bash_orch_if bash_path_ident_ok delegates). Predicate operands carrying POSIX quoting/expansion characters refuse (PredicateOperandCarriesShellSpelling) rather than silently comparing as literals -- the consumer-varying meaning fork recorded on gunbc.recurring_failure_mode.meaning_fork; dissolves when Predicate operands are Expr. Evidence: real-execution witnesses per arm (observe through the bound variable, exact stdout round-trip, observed branch), metacharacter REDs, For/While/Retry control, and the three Unsupported* assertions flipped to permanent regression controls. New witness identities enrolled in floor_route_gap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gwiHZMAPm5jevzYYoiJPC
…lete the alias Review 66070: the delegating body referenced posix_name_ok without importing it, and bash_path_ident_ok was a second name for the POSIX name rule. The import lands, the alias deletes, and the three sites read posix_name_ok. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gwiHZMAPm5jevzYYoiJPC
|
Review 66070, both findings fixed in 8fc2bac: (1) — sent from clever-pike-500 |
…et lane The ten members of test.claim.effect_plan_bash_materialize_real_execution_witness enroll on local_repo_wet_schedule so each changed identity's hermetic route gap on shell.Exec.Run joins a wet terminal (HermeticRouteGapHeldAndWetPassed); measured on run 34823848386 as changed_witness_planned_without_terminal_verdict. The file's ci_layer_roots row moves from the bin-witness wet class (standing carried by excl_bin_wet_reason) to LocalRepoWetLane with its own reason and dissolution. Route-gap rows stay; nothing is unenrolled or dropped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gwiHZMAPm5jevzYYoiJPC
|
Floor RED on 8fc2bac ( — sent from clever-pike-500 |
… bin-wet class (review 66111) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gwiHZMAPm5jevzYYoiJPC
…eview 66126) The climb keeps the flipped assertions enrolled as regression controls and deletes the constructors nothing produces (DESIGN 4b(4)); the label fold shrinks with the coproduct. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gwiHZMAPm5jevzYYoiJPC
|
Review 66126: agreed and fixed in c615248. — sent from clever-pike-500 |
What this lands
v2.workflow.effect_plan_bash_materializenow materializes theIf,LetandCallarms ofv2.std.effect_plan EffectPlanStep, which it previously refused withEffectPlanBashUnsupportedStep UnsupportedIf / UnsupportedLet / UnsupportedCall.For,WhileandRetrykeep refusing with their unchanged causes; nothing demands them.All three arms lower through the grammar rows the
Doarm already emits and serialize through the one serializer (bash_command_fold_serialize); there is no second bash emitter and nothing routes throughv2.std.orchestration Pipeline/PipelineStep.Let { name, ExprLit }bash_build_assign_litNAME='value'Let { name, ExprVarRef }bash_build_assign_varNAME="$SOURCE"Let { name, ExprCmdSubst }bash_build_assignoverbash_build_word_cmdsubstNAME=$('callee' 'arg' …)Call { callee, args }bash_build_command_from_lits'callee' 'arg' …If { cond, then_, Absent }bash_build_ifif COND; then BODY; fiIf { cond, then_, Present }bash_build_if_else(new builder tag, serializer binds the existingbash_orch_if bash_stmt_if_else_target_model; same precedent asbash_build_negation)if COND; then A; else B; fiStrEq / StrEmpty / StrNonempty / IntNebash_build_test_bracket'[' 'a' '=' 'b' ']'etc.Not / And / Orbash_build_negation/bash_build_and_then/bash_build_or_else! …,… && …,… || …Branch bodies are encoded by the same fold as the top-level plan, so FailFast inside a branch is the same
&&relation; a refusal inside a branch surfaces at theIfstep asNestedBranchRefused { branch, refusal }.Quoting is the safety subject
Every interpolated value is a
bash_token_litword and goes through the existing quoting authority (extdeps.posix.shell_command_language posix_single_quote). Names are the one position quoting cannot cover — a variable name renders bare inname=and inside"$name"— soLetnames andExprVarRefnames must satisfy the POSIX name rule (XBD 3.235) or refuseShellNameInvalid. That rule now has one home,posix_name_okinextdeps.posix.shell_command_languagebesideposix_single_quote;bash_orch_if bash_path_ident_okdelegates to it (it had its own copy of the alphabets, and importingbash_orch_iffrom the materializer would have been a new realization-vocabulary leak).Typed refusals, none of which emit anything:
ShellNameInvalid { name }—Letname /ExprVarRefname outside the POSIX name rule.ArgumentContainsNul { argument_index }— NUL in a Let value, cmdsubst word, Call word or predicate operand (the one byte no quoting carries; same arm the Do path uses).CallCalleeEmpty— a plan that calls nothing.IntNeOperandNotDecimalInteger { operand }—[ a -ne 1 ]prints an error and takes the ELSE branch with status 2, a wrong answer wearing a diagnostic.PredicateOperandCarriesShellSpelling { operand }— see the fork below.UnsupportedPredicate { ExitZeroRunPredicate | LogMatchesPredicate }—ExitZerocarries aRunwhose command is a raw string;LogMatcheshas no grep argv authority (extdeps.tools.grepis a tool row only).IfBranchEmpty { branch }—then ; fiis a syntax error.NestedBranchRefused { branch, refusal }.effect_plan_bash_refusal_labelstays total over the widened coproduct.The meaning fork this surfaced, and the disposition taken
v2.std.orchestration Predicateoperands are bareString. The Pipeline string tier (05_emit_orchestration) reads them as raw shell spellings — its authors writelhs: "\"$X\"". This transport reads an operand as a value and quotes it, so that spelling would silently compare four literal characters. That is the consumer-varying form ofgunbc.recurring_failure_mode.meaning_fork; a receipt and evidence are appended to that row (not a new row). Disposition: operands carrying any of$ \" ' ` refuse withPredicateOperandCarriesShellSpelling. That is a bounded, loud over-prohibition of a quotable literal, with its dissolution named in the module: Predicate operands carried asExpr(ExprLit | ExprVarRef | ExprCmdSubst, which already exists beside Predicate in the same module).What that means for the consumer, stated plainly: with this PR,
Ifcompares literals only. gunbc-private#60's pin check isLeta captured revision, thenIfon that variable — that needs a variable-reference operand, whichPredicatecannot yet express. So this PR satisfies #60's trigger text exactly as written (the three arms materialize rather than refuse), but the Predicate→Expr operand migration inv2.std.orchestrationis the remaining capability #60'sIfshape needs. That migration touches every string-tierPredicateauthor and their goldens; it is not this PR and I have not started it. Flagged to bright-eagle-728 for a decision on whether it is the next lane.Evidence, per arm
Real execution (
test.claim.effect_plan_bash_materialize_real_execution_witness, materialize →bash_materialized_transport→ bash, observed effect):Let TOOL='id'then aDowhose argv[0] isHostEnvVar TOOLexecutesid -uthrough the bound variable (lit, var-ref chain, cmdsubst). RED:id; printf PWN, a cmdsubst arg with the same payload, and a newline payload each stay one word: command-not-found, no output.printf '%s' <payload>witha'b; $(id) \id` | printf PWN > /dev/null "x" \ $HOME— stdout equals the payload byte-for-byte. RED: a calleetrue; printf PWN/true\nprintf PWN` is a name, cannot run, and FailFast stops the plan.then/elsebranch observed by which printf runs,Not, and sequencing with a following step. RED: an operanda; printf PWN | id -ucompares as one word (eqwhen equal,newhen not). A failingDoinside a then-branch stops the branch and the plan.Unit (
v2.test.claim.effect_plan_bash_materialize_test): exact emitted bytes per arm, metacharacter round-trip for Let value / Call arg / If operand, every new refusal arm asserted at its step index with its cause, the label fold rendering a nested refusal, and:effect_plan_bash_RED_for_while_retry_still_refuse_with_unchanged_causes;effect_plan_bash_if_let_call_no_longer_refuse_as_unsupported— the formerUnsupportedIf/Let/Callexpecting-red assertions flipped, not deleted; the arms stay in the coproduct.The seven new witness identities reach
shell.Exec.Runon the hermetic floor exactly as the file's existing three do and are enrolled infloor_route_gapchunk_11 at the same operation and ground.Consumer (DESIGN 3c)
Consumed by execution in this change: the witnesses above. Named later consumer: gunbc-private#60 (
strategy.private_witness_workflow), whose declared debtannotation_step_shell_medium_dissolutionreads: "v2.workflow.effect_plan_bash_materialize materializes EffectPlanStep If, Let and Call rather than refusing them with EffectPlanBashUnsupportedStep UnsupportedIf / UnsupportedLet / UnsupportedCall -- the model side (v2.std.effect_plan) already expresses these steps, only the bash transport refuses them". gunbc-private is not edited here.posix_name_okis consumed bybash_path_ident_ok(three existing call sites) and by the materializer.Not in scope
For,While,Retry;ExitZero/LogMatchespredicates; the Predicate→Expr operand migration;v2.std.orchestration Pipeline/PipelineStep.🤖 Generated with Claude Code
https://claude.ai/code/session_016gwiHZMAPm5jevzYYoiJPC