Skip to content

feat(shell): && || ; sequencing, increment 4 (#34)#41

Merged
hartsock merged 1 commit into
mainfrom
issue-34/sequencing
Jun 25, 2026
Merged

feat(shell): && || ; sequencing, increment 4 (#34)#41
hartsock merged 1 commit into
mainfrom
issue-34/sequencing

Conversation

@hartsock

Copy link
Copy Markdown
Member

Increment 4 of #34 (ADR 0005 D3): the safe-subset engine now runs sequences — pipelines joined by && / || / ; with bash short-circuit semantics.

What

  • parse.rsclassify() returns a Script = Vec<ScriptItem { sep, pipeline }> (Sep::Seq/And/Or; first item is Seq). Leading/doubled/dangling separators and dangling pipes are Malformed; quoted operators stay literal (echo "a&&b" is one argv).
  • shell_tool.rsrun_script folds the AND-OR list: ; unconditional, && iff prev exit 0, || iff prev exit ≠ 0; output of the pipelines that ran is concatenated in order; exit = last pipeline that ran. The Spawner seam is unchanged (one run() per pipeline) — sequencing is orchestration, so it's fully mock-testable.

Security

Atomic admission widened to the whole script: an out-of-scope program or redirect target anywhere — even one a &&/|| would short-circuit away — denies everything before any spawn (no partial side effects).

Testing (fully mocked + deep)

  • Unit (per-program mock exit codes, no real processes): false && echo skips echo; false || echo runs it; true || echo skips; ; unconditional; combined output concatenates in order; out-of-scope command anywhere denies the whole script with nothing spawned; a dynamic stage in a sequence is refused.
  • Integration (real): true && echo, false && echo (skipped), false || echo (fallback), echo a ; echo b.

Test plan

just check green (fmt + clippy all-features & no-default-features + workspace tests). Part of #34.

🤖 Generated with Claude Code

WHAT: The safe-subset engine now parses a Script — a sequence of pipelines joined by && / || / ; (Sep::And/Or/Seq). parse.rs builds Vec<ScriptItem{sep, pipeline}> (first item is Seq); leading/doubled/dangling separators and dangling pipes are Malformed; quoted operators stay literal. run_script executes the bash AND-OR-list short-circuit: ; runs unconditionally, && runs iff prev exit==0, || runs iff prev exit!=0; output of the pipelines that ran is concatenated in order; exit = last pipeline that ran.

WHY: && / || / ; are core agent ergonomics (cd x && build, try || fallback). The Spawner seam is unchanged (still one run() per pipeline) — sequencing is orchestration in run_script, so it is fully mock-testable. Atomic admission is widened to the WHOLE script: an out-of-scope program or redirect ANYWHERE (even one a && / || would short-circuit away) denies everything before any spawn — no partial side effects.

TEST: 19 unit (mock-spawner short-circuit: && skips on failure, || runs on failure, ; unconditional, true|| skips, combined output order, atomic admission across the script, dynamic-stage refused) + 10 real-spawn integration (true&&echo, false&&echo skipped, false||echo fallback, echo;echo). just check green (fmt + clippy all-features & no-default-features + workspace tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01HMGPEApE4XfwgMhgFbRn6c
@hartsock hartsock added the risk:low Low-risk change label Jun 25, 2026
@hartsock hartsock merged commit 95d9c8a into main Jun 25, 2026
1 check passed
@hartsock hartsock deleted the issue-34/sequencing branch June 25, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:low Low-risk change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant