Skip to content

Commit 8526222

Browse files
Copilotmrjf
andauthored
Add repo-memory clone step before scheduling pre-step
The repo-memory clone step (from the tools: section) was placed after the "Check which programs are due" pre-step by the gh-aw compiler, so the scheduling script could not read persisted state from previous runs. This caused incorrect selection/skip behavior. Fix: add an explicit shallow clone of the memory/autoloop branch as a new pre-step that runs before the scheduling step, ensuring state files are available when scheduling decisions are made. Also adds tests to verify the step ordering invariant. Agent-Logs-Url: https://github.com/githubnext/autoloop/sessions/3013e45a-953d-4f06-bdab-ed720379b412 Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
1 parent 402c501 commit 8526222

2 files changed

Lines changed: 80 additions & 0 deletions

File tree

tests/test_scheduling.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,3 +680,61 @@ def test_get_program_name_extracted(self):
680680
def test_read_program_state_extracted(self):
681681
# read_program_state exists in the workflow but depends on file I/O
682682
assert "read_program_state" in _funcs
683+
684+
685+
# ---------------------------------------------------------------------------
686+
# Workflow step ordering — repo-memory must be available before scheduling
687+
# ---------------------------------------------------------------------------
688+
689+
class TestWorkflowStepOrdering:
690+
"""Verify that the repo-memory clone step appears before the scheduling step.
691+
692+
The scheduling pre-step reads persisted state from repo-memory. If the
693+
clone happens after scheduling, the script cannot see previous-run state,
694+
causing incorrect selection/skip behaviour.
695+
"""
696+
697+
def _load_steps(self):
698+
"""Return the list of pre-step names from workflows/autoloop.md."""
699+
import os, re, yaml
700+
wf_path = os.path.join(os.path.dirname(__file__), "..", "workflows", "autoloop.md")
701+
with open(wf_path) as f:
702+
content = f.read()
703+
# The YAML frontmatter (before `---` + markdown body) contains the steps.
704+
# Extract the frontmatter block (first --- ... --- block including 'steps:').
705+
# The source file has the structure: ---\n<yaml>\n---\nsteps:\n - ...\n\nsource: ...
706+
# We need everything from start to the line "source: ..." or "engine: ..."
707+
# Actually, the whole pre-body section is YAML-ish; let's just find step names.
708+
step_names = []
709+
for m in re.finditer(r'^\s*-\s*name:\s*(.+)$', content, re.MULTILINE):
710+
step_names.append(m.group(1).strip())
711+
return step_names
712+
713+
def test_clone_step_exists(self):
714+
"""A step that clones repo-memory for scheduling must exist."""
715+
steps = self._load_steps()
716+
clone_steps = [s for s in steps if "repo-memory" in s.lower() and "schedul" in s.lower()]
717+
assert len(clone_steps) >= 1, (
718+
"Expected a repo-memory clone step for scheduling, found none. "
719+
f"Steps: {steps}"
720+
)
721+
722+
def test_clone_before_scheduling(self):
723+
"""The repo-memory clone step must come before 'Check which programs are due'."""
724+
steps = self._load_steps()
725+
clone_idx = None
726+
sched_idx = None
727+
for i, name in enumerate(steps):
728+
if "repo-memory" in name.lower() and "schedul" in name.lower():
729+
clone_idx = i
730+
break
731+
for i, name in enumerate(steps):
732+
if name == "Check which programs are due":
733+
sched_idx = i
734+
break
735+
assert clone_idx is not None, f"Clone step not found. Steps: {steps}"
736+
assert sched_idx is not None, f"Scheduling step not found. Steps: {steps}"
737+
assert clone_idx < sched_idx, (
738+
f"Clone step (index {clone_idx}) must come before scheduling step "
739+
f"(index {sched_idx}). Steps: {steps}"
740+
)

workflows/autoloop.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,28 @@ imports:
8181
- shared/reporting.md
8282

8383
steps:
84+
- name: Clone repo-memory for scheduling
85+
env:
86+
GH_TOKEN: ${{ github.token }}
87+
GITHUB_REPOSITORY: ${{ github.repository }}
88+
GITHUB_SERVER_URL: ${{ github.server_url }}
89+
run: |
90+
# Clone the repo-memory branch so the scheduling step can read persisted state
91+
# from previous runs. The framework-managed repo-memory clone happens after
92+
# pre-steps, so we perform an early shallow clone here.
93+
MEMORY_DIR="/tmp/gh-aw/repo-memory/autoloop"
94+
BRANCH="memory/autoloop"
95+
mkdir -p "$(dirname "$MEMORY_DIR")"
96+
REPO_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
97+
AUTH_URL="$(echo "$REPO_URL" | sed "s|https://|https://x-access-token:${GH_TOKEN}@|")"
98+
if git ls-remote --exit-code --heads "$AUTH_URL" "$BRANCH" > /dev/null 2>&1; then
99+
git clone --single-branch --branch "$BRANCH" --depth 1 "$AUTH_URL" "$MEMORY_DIR" 2>&1
100+
echo "Cloned repo-memory branch to $MEMORY_DIR"
101+
else
102+
mkdir -p "$MEMORY_DIR"
103+
echo "No repo-memory branch found yet (first run). Created empty directory."
104+
fi
105+
84106
- name: Check which programs are due
85107
env:
86108
GITHUB_TOKEN: ${{ github.token }}

0 commit comments

Comments
 (0)