This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git
The following commit(s) were added to refs/heads/main by this push:
new 479f0724 fix(spec-loop): make loop.sh argument handling explicit (#472)
479f0724 is described below
commit 479f0724e58a985a150f91ed3efbdade80020c0f
Author: Justin Mclean <[email protected]>
AuthorDate: Thu Jun 11 18:21:00 2026 +1000
fix(spec-loop): make loop.sh argument handling explicit (#472)
---
tools/spec-loop/loop.sh | 62 +++++++++++++++++++++++++++++++++++--------------
1 file changed, 45 insertions(+), 17 deletions(-)
diff --git a/tools/spec-loop/loop.sh b/tools/spec-loop/loop.sh
index c5b22c25..966c5eef 100755
--- a/tools/spec-loop/loop.sh
+++ b/tools/spec-loop/loop.sh
@@ -7,12 +7,14 @@
# A small loop in the general "Ralph" style (run a fresh agent context
# against a prompt, repeat), adapted to this framework's posture:
#
-# * THREE modes, ONE mechanism:
+# * FOUR modes, ONE mechanism:
# ./loop.sh build, unlimited iterations
# ./loop.sh 20 build, max 20 iterations
+# ./loop.sh build [N] build, max N iterations (N=0/omitted =
unlimited)
# ./loop.sh plan [N] gap-analysis only, updates the plan (default
1 pass; N=0 unlimited)
# ./loop.sh update [N] back-fill specs from code others contributed
(default 1 pass; N=0 unlimited)
# ./loop.sh consolidate [N] shrink the plan (default 1 pass; N=0
unlimited)
+# ./loop.sh -h | --help show usage and exit
# * BRANCH PER WORK ITEM: before each build iteration the loop returns
# to the integration base; the build prompt then carves out
# <slug> for the one work item it implements. One work item =
@@ -92,22 +94,48 @@ PR_LIMIT="${SPEC_LOOP_PR_LIMIT:-100}"
PLAN_CONSOLIDATE_THRESHOLD="${SPEC_LOOP_PLAN_MAX:-500}"
# ---- parse arguments -------------------------------------------------
-if [ "${1:-}" = "plan" ]; then
- MODE="plan"; PROMPT_FILE="$LOOP_DIR/PROMPT_plan.md";
MAX_ITERATIONS="${2:-1}"
-elif [ "${1:-}" = "update" ]; then
- MODE="update"; PROMPT_FILE="$LOOP_DIR/PROMPT_update.md";
MAX_ITERATIONS="${2:-1}"
-elif [ "${1:-}" = "consolidate" ]; then
- MODE="consolidate"; PROMPT_FILE="$LOOP_DIR/PROMPT_consolidate.md";
MAX_ITERATIONS="${2:-1}"
-elif [[ "${1:-}" =~ ^[0-9]+$ ]]; then
- MODE="build"; PROMPT_FILE="$LOOP_DIR/PROMPT_build.md";
MAX_ITERATIONS="$1"
-else
- MODE="build"; PROMPT_FILE="$LOOP_DIR/PROMPT_build.md";
MAX_ITERATIONS=0
-fi
+usage() {
+ cat <<'EOF'
+Spec-driven build loop.
+
+Usage:
+ ./loop.sh [N] build; N iterations (omit or 0 = unlimited)
+ ./loop.sh build [N] same as above, explicit
+ ./loop.sh plan [N] gap-analysis only, updates the plan (default 1;
0 = unlimited)
+ ./loop.sh update [N] back-fill specs from contributed code (default
1; 0 = unlimited)
+ ./loop.sh consolidate [N] shrink the plan (default 1; 0 = unlimited)
+ ./loop.sh -h | --help show this help
+
+Stop gracefully: Ctrl+C, or `touch STOP` (exits after the current iteration).
+EOF
+}
-# Reject a non-numeric iteration count. The plan/update/consolidate second
-# argument flows straight into the integer comparisons below, where a typo'd
-# value would otherwise error to stderr and be silently treated as 0 — i.e.
-# run unbounded instead of failing.
+# The iteration count is the SECOND arg for the named modes, and the FIRST
+# (bare number) for build. `build [N]` is also accepted so the count position
+# is consistent across every mode. An unknown first argument is an error —
+# it must never fall through to an unbounded build run.
+case "${1:-}" in
+ -h|--help|help)
+ usage; exit 0 ;;
+ plan) MODE="plan"; PROMPT_FILE="$LOOP_DIR/PROMPT_plan.md";
MAX_ITERATIONS="${2:-1}" ;;
+ update) MODE="update"; PROMPT_FILE="$LOOP_DIR/PROMPT_update.md";
MAX_ITERATIONS="${2:-1}" ;;
+ consolidate) MODE="consolidate";
PROMPT_FILE="$LOOP_DIR/PROMPT_consolidate.md"; MAX_ITERATIONS="${2:-1}" ;;
+ build) MODE="build"; PROMPT_FILE="$LOOP_DIR/PROMPT_build.md";
MAX_ITERATIONS="${2:-0}" ;;
+ "") MODE="build"; PROMPT_FILE="$LOOP_DIR/PROMPT_build.md";
MAX_ITERATIONS=0 ;;
+ *)
+ if [[ "$1" =~ ^[0-9]+$ ]]; then
+ MODE="build"; PROMPT_FILE="$LOOP_DIR/PROMPT_build.md";
MAX_ITERATIONS="$1"
+ else
+ echo "Error: unknown argument '$1'." >&2
+ echo >&2
+ usage >&2
+ exit 1
+ fi ;;
+esac
+
+# Reject a non-numeric iteration count (e.g. `plan abc`, `build 2x`). Without
+# this the value would flow into the integer comparisons below, error to
+# stderr, and be silently treated as 0 — i.e. run unbounded instead of failing.
if ! [[ "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
echo "Error: iteration count must be a non-negative integer, got
'${MAX_ITERATIONS}'." >&2
exit 1
@@ -127,7 +155,7 @@ echo "Prompt: $PROMPT_FILE"
echo "Base: $BASE (work items fork from here)"
echo "Agent: $AGENT"
echo "Model: $MODEL"
-[ "$MAX_ITERATIONS" -gt 0 ] && echo "Max: $MAX_ITERATIONS iterations"
+if [ "$MAX_ITERATIONS" -gt 0 ]; then echo "Max: $MAX_ITERATIONS
iterations"; else echo "Max: unlimited"; fi
echo "Stop: Ctrl+C or touch STOP"
echo "Note: this loop never pushes and never opens a PR."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"