Skip to content

Commit 14687fd

Browse files
Copilotmrjf
andauthored
Merge origin/main to resolve PR conflicts
Co-authored-by: mrjf <180956+mrjf@users.noreply.github.com>
2 parents 0fbd161 + c99c155 commit 14687fd

296 files changed

Lines changed: 54607 additions & 2459 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/autoloop.lock.yml

Lines changed: 22 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/autoloop.md

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ on:
2424

2525
permissions: read-all
2626

27-
timeout-minutes: 45
27+
timeout-minutes: 360
2828

2929
network:
3030
allowed:
@@ -45,6 +45,7 @@ safe-outputs:
4545
title-prefix: "[Autoloop] "
4646
labels: [automation, autoloop]
4747
protected-files: fallback-to-issue
48+
preserve-branch-name: true
4849
max: 1
4950
push-to-pull-request-branch:
5051
target: "*"
@@ -434,10 +435,26 @@ steps:
434435
# Look up existing PR for the selected program's canonical branch
435436
existing_pr = None
436437
head_branch = None
438+
439+
def verify_pr_is_open(pr_number):
440+
"""Check if a PR is still open via the GitHub API. Returns True if open."""
441+
try:
442+
verify_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}"
443+
verify_req = urllib.request.Request(verify_url, headers={
444+
"Authorization": f"token {github_token}",
445+
"Accept": "application/vnd.github.v3+json",
446+
})
447+
with urllib.request.urlopen(verify_req, timeout=30) as verify_resp:
448+
pr_data = json.loads(verify_resp.read().decode())
449+
return pr_data.get("state") == "open"
450+
except Exception:
451+
return True # If we can't verify, assume it's open (best effort)
452+
437453
if selected:
438454
head_branch = f"autoloop/{selected}"
439455
owner = repo.split("/")[0] if "/" in repo else ""
440456
if owner:
457+
# Strategy 1: exact branch match (works when branch has no framework suffix)
441458
try:
442459
pr_api_url = (
443460
f"https://api.github.com/repos/{repo}/pulls"
@@ -451,22 +468,54 @@ steps:
451468
open_prs = json.loads(pr_resp.read().decode())
452469
if open_prs:
453470
existing_pr = open_prs[0]["number"]
454-
print(f" Found existing PR #{existing_pr} for branch {head_branch}")
455-
else:
456-
print(f" No existing PR found for branch {head_branch}")
471+
print(f" Found existing PR #{existing_pr} for exact branch {head_branch}")
457472
except Exception as e:
458-
print(f" Warning: could not check for existing PRs: {e}")
473+
print(f" Warning: could not check for existing PRs by exact branch: {e}")
474+
475+
# Strategy 2: search by title and branch prefix (catches framework-generated
476+
# hash suffixes like autoloop/name-a1b2c3d4e5f6g7h8 created by create-pull-request)
477+
if existing_pr is None:
478+
try:
479+
title_marker = f"[Autoloop: {selected}]"
480+
branch_prefix = head_branch # e.g. autoloop/perf-comparison
481+
list_url = (
482+
f"https://api.github.com/repos/{repo}/pulls"
483+
f"?state=open&per_page=100&sort=created&direction=desc"
484+
)
485+
list_req = urllib.request.Request(list_url, headers={
486+
"Authorization": f"token {github_token}",
487+
"Accept": "application/vnd.github.v3+json",
488+
})
489+
with urllib.request.urlopen(list_req, timeout=30) as list_resp:
490+
all_open_prs = json.loads(list_resp.read().decode())
491+
# Match branch names: exact canonical name or canonical + framework hash suffix
492+
branch_pattern = re.compile(r'^' + re.escape(branch_prefix) + r'(-[0-9a-f]{16})?$')
493+
for pr in all_open_prs:
494+
pr_title = pr.get("title", "")
495+
pr_head_ref = pr.get("head", {}).get("ref", "")
496+
if title_marker in pr_title or branch_pattern.match(pr_head_ref):
497+
existing_pr = pr["number"]
498+
print(f" Found existing PR #{existing_pr} by title/branch-prefix (branch: {pr_head_ref})")
499+
break
500+
if existing_pr is None:
501+
print(f" No existing PR found for program {selected}")
502+
except Exception as e:
503+
print(f" Warning: could not search for existing PRs by title/prefix: {e}")
459504
else:
460505
print(f" Warning: could not parse owner from GITHUB_REPOSITORY='{repo}'")
461506
462-
# Also check the state file for a recorded PR number as fallback
507+
# Strategy 3: check the state file for a recorded PR number as fallback
463508
if existing_pr is None:
464509
state = read_program_state(selected)
465510
pr_field = state.get("pr") or ""
466511
pr_match = re.match(r'^#?(\d+)$', pr_field.strip())
467512
if pr_match:
468-
existing_pr = int(pr_match.group(1))
469-
print(f" Found PR #{existing_pr} from state file for {selected}")
513+
pr_num = int(pr_match.group(1))
514+
if verify_pr_is_open(pr_num):
515+
existing_pr = pr_num
516+
print(f" Found open PR #{existing_pr} from state file for {selected}")
517+
else:
518+
print(f" PR #{pr_num} from state file is no longer open — ignoring")
470519
471520
result = {
472521
"selected": selected,

.github/workflows/evergreen.lock.yml

Lines changed: 19 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/evergreen.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ on:
1515

1616
permissions: read-all
1717

18-
timeout-minutes: 30
18+
timeout-minutes: 360
1919

2020
network:
2121
allowed:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ dist/
33
*.tsbuildinfo
44
package-lock.json
55
*.tgz
6+
playground/benchmarks/
7+
playground/dist/
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
"""Benchmark: pd.Categorical.from_codes on 100k-element code array"""
1+
"""Benchmark: Categorical from codes on 100k-element array"""
22
import json, time
3+
import numpy as np
34
import pandas as pd
45

56
ROWS = 100_000
67
WARMUP = 3
78
ITERATIONS = 10
8-
categories = ["alpha", "beta", "gamma", "delta"]
9-
codes = [i % 4 for i in range(ROWS)]
9+
10+
categories = ["apple", "banana", "cherry", "date", "elderberry"]
11+
codes = np.arange(ROWS) % len(categories)
1012

1113
for _ in range(WARMUP):
1214
pd.Categorical.from_codes(codes, categories=categories)
@@ -15,4 +17,5 @@
1517
for _ in range(ITERATIONS):
1618
pd.Categorical.from_codes(codes, categories=categories)
1719
total = (time.perf_counter() - start) * 1000
18-
print(json.dumps({"function": "cat_from_codes", "mean_ms": total / ITERATIONS, "iterations": ITERATIONS, "total_ms": total}))
20+
21+
print(json.dumps({ "function": "cat_from_codes", "mean_ms": total / ITERATIONS, "iterations": ITERATIONS, "total_ms": total }))

benchmarks/pandas/bench_cut.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Benchmark: cut bin 100k values into 10 equal-width bins"""
1+
"""Benchmark: cut (bin into 10 bins) on 100k-element Series"""
22
import json, time
33
import numpy as np
44
import pandas as pd
@@ -7,21 +7,15 @@
77
WARMUP = 3
88
ITERATIONS = 10
99

10-
data = np.arange(ROWS, dtype=np.float64) % 100
10+
data = (np.arange(ROWS) % 10000) * 0.01
1111
s = pd.Series(data)
12-
bins = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
1312

1413
for _ in range(WARMUP):
15-
pd.cut(s, bins)
14+
pd.cut(s, 10)
1615

1716
start = time.perf_counter()
1817
for _ in range(ITERATIONS):
19-
pd.cut(s, bins)
18+
pd.cut(s, 10)
2019
total = (time.perf_counter() - start) * 1000
2120

22-
print(json.dumps({
23-
"function": "cut",
24-
"mean_ms": total / ITERATIONS,
25-
"iterations": ITERATIONS,
26-
"total_ms": total,
27-
}))
21+
print(json.dumps({ "function": "cut", "mean_ms": total / ITERATIONS, "iterations": ITERATIONS, "total_ms": total }))
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
"""Benchmark: dataframe cov on a 10k-row, 10-column DataFrame"""
1+
"""Benchmark: DataFrame covariance matrix on 1000x10 DataFrame"""
22
import json, time
33
import numpy as np
44
import pandas as pd
55

6-
ROWS = 10_000
6+
ROWS = 1_000
77
COLS = 10
88
WARMUP = 3
99
ITERATIONS = 10
@@ -19,9 +19,4 @@
1919
df.cov()
2020
total = (time.perf_counter() - start) * 1000
2121

22-
print(json.dumps({
23-
"function": "dataframe_cov",
24-
"mean_ms": total / ITERATIONS,
25-
"iterations": ITERATIONS,
26-
"total_ms": total,
27-
}))
22+
print(json.dumps({ "function": "dataframe_cov", "mean_ms": total / ITERATIONS, "iterations": ITERATIONS, "total_ms": total }))

benchmarks/pandas/bench_ewm_std.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Benchmark: EWM std (span=20) on 100k-element Series"""
1+
"""Benchmark: ewm std (alpha=0.1) on 100k-element Series"""
22
import json, time
33
import numpy as np
44
import pandas as pd
@@ -11,16 +11,11 @@
1111
s = pd.Series(data)
1212

1313
for _ in range(WARMUP):
14-
s.ewm(span=20).std()
14+
s.ewm(alpha=0.1).std()
1515

1616
start = time.perf_counter()
1717
for _ in range(ITERATIONS):
18-
s.ewm(span=20).std()
18+
s.ewm(alpha=0.1).std()
1919
total = (time.perf_counter() - start) * 1000
2020

21-
print(json.dumps({
22-
"function": "ewm_std",
23-
"mean_ms": total / ITERATIONS,
24-
"iterations": ITERATIONS,
25-
"total_ms": total,
26-
}))
21+
print(json.dumps({ "function": "ewm_std", "mean_ms": total / ITERATIONS, "iterations": ITERATIONS, "total_ms": total }))

benchmarks/pandas/bench_ewm_var.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Benchmark: EWM var (span=20) on 100k-element Series"""
1+
"""Benchmark: ewm var (alpha=0.1) on 100k-element Series"""
22
import json, time
33
import numpy as np
44
import pandas as pd
@@ -11,16 +11,11 @@
1111
s = pd.Series(data)
1212

1313
for _ in range(WARMUP):
14-
s.ewm(span=20).var()
14+
s.ewm(alpha=0.1).var()
1515

1616
start = time.perf_counter()
1717
for _ in range(ITERATIONS):
18-
s.ewm(span=20).var()
18+
s.ewm(alpha=0.1).var()
1919
total = (time.perf_counter() - start) * 1000
2020

21-
print(json.dumps({
22-
"function": "ewm_var",
23-
"mean_ms": total / ITERATIONS,
24-
"iterations": ITERATIONS,
25-
"total_ms": total,
26-
}))
21+
print(json.dumps({ "function": "ewm_var", "mean_ms": total / ITERATIONS, "iterations": ITERATIONS, "total_ms": total }))

0 commit comments

Comments
 (0)