Methodology

Probe implementation

The actual source that drives every probe in this report — read straight from scripts/ at build time. 4 files, 865 lines. This is the real logic, not a paraphrase.

How the probe engine works

Two-phase discovery-then-finalize

Each table is probed in two phases. First a *discovery* pass probes candidate filter-value maps once and picks the winning set (the one returning the most rows with no error) — the default map is tried first and short-circuits if it succeeds, so the common case is a single discovery probe. Then the canonical `minimal` / `realistic` / `edge` variants run against only that winning value set. Exploration failures (non-existent alternate paths, wrong repo names) are never counted against the final verdict, so a working table is not dragged to 'partial' by a bad alternate value.

VALUE_ALTERNATES

A per-filter dictionary of real candidate values (`org`: anomalyco/sst, `owner`: FiscalMindset/anomalyco/sst, `repo`: opencode/linux/Hello-World, `path`: ''/README.md/src, plus `branch`, `installation_id`, `app_slug`). The discovery pass walks these so a table passes if ANY real value set returns rows. The actual GitHub App for this project is installed on the `FiscalMindset` user account (installation 158026446), and the `anomalyco` / `sst` orgs exist.

429 rate-limit retry + backoff

GitHub applies aggressive secondary rate limits; a burst of probes trips 429s that would otherwise falsely fail a probe. `run_coral_sql` detects a 'rate limit' error and retries the query with a 60-second backoff (2 retries), and the final verdict computes on the canonical variants after discovery. This makes a pass verdict meaningful — it reflects the endpoint, not transient throttling.

Version-preserving reports

Every re-probe archives the previous canonical result to `reports/<source>/tables/<name>.history/<timestamp>.json` (append-only) and writes the new result to the canonical file, bumping `history.retry_count`. Nothing is ever deleted — the site shows conversion progress over time and versions.

probe_batch.py

The probe engine. Builds filter-value probes, runs them through `coral sql`, and writes the version-preserving per-table report (canonical + `.history/`).

/opt/render/project/src/scripts/probe_batch.py

1#!/usr/bin/env python3
2"""In-process version of probe_batch: reuses one `coral sql` subprocess
3per worker, no per-table spawn overhead. Each table does 3 variants ×
4N trials = 6 coral calls (~10s each on github).
5
6For 364 tables with 4 workers ≈ 30 min (vs ~4 hours via probe_table.py).
7
8Usage:
9 python3 scripts/probe_batch.py --source github [--workers 4]
10"""
11import argparse, json, os, statistics, subprocess, sys, time
12from concurrent.futures import ThreadPoolExecutor, as_completed
13from pathlib import Path
14
15DEFAULT_FILTER_VALUES = {
16 "owner": "anomalyco", "repo": "opencode", "org": "anomalyco",
17 "username": "FiscalMindset", "enterprise": "github",
18 "plan_id": "1", "assignment_id": "1", "app_slug": "coral-benchmarks-connector",
19 "gist_id": "1", "subject_digest": "sha256:0000",
20 "branch": "main", "ref": "main", "issue_number": "1",
21 "pull_number": "1", "alert_number": "1", "attempt_number": "1",
22 "run_id": "1", "check_run_id": "1", "hook_id": "1",
23 "runner_group_id": "1", "environment_name": "production",
24 "commit_sha": "main", "repository_id": "1296269",
25 "file_sha": "main", "tag_name": "v1", "build_id": "1",
26 "analysis_id": "1", "sarif_id": "1", "delivery_id": "1",
27 "deployment_id": "1", "job_id": "1", "secret_name": "1",
28 "variable_name": "1", "key": "1", "page": "1",
29 "installation_id": "158026446", "rule_id": "1", "rule_suite_id": "1",
30 "comment_id": "1", "event_id": "1", "label_name": "bug",
31 "artifact_id": "1", "delivery_id": "1",
32 "workflow_file_name": "test.yml",
33}
34
35# Alternate candidate values applied per-filter when the default set 404s.
36# Each key maps to a list of fallback values tried before giving up.
37VALUE_ALTERNATES = {
38 "org": ["anomalyco", "sst"],
39 "owner": ["anomalyco", "FiscalMindset", "sst"],
40 "repo": ["opencode", "linux", "Hello-World"],
41 "username": ["FiscalMindset", "anomalyco"],
42 "path": ["", "README.md", "src"],
43 "installation_id": ["158026446", "1"],
44 "app_slug": ["coral-benchmarks-connector", "opencode"],
45}
46
47# Map: git/runs/etc. categorical keys to a discovery file list.
48# Loaded from scripts/data/github_discovered_values.json if present.
49DISCOVERED_FILTERS = {
50 "issue_number": "issue_numbers",
51 "pull_number": "pr_numbers",
52 "run_id": "workflow_runs",
53 "check_run_id": "check_run_ids",
54 "artifact_id": "artifact_ids",
55 "job_id": "job_ids",
56 "commit_sha": "commit_shas",
57 "tag_name": "tags",
58 "environment_name": "environments",
59 "label_name": "labels",
60 "comment_id": "comment_ids",
61 "event_id": "event_ids",
62 "delivery_id": "event_ids",
63}
64
65def load_discovered_values(path="scripts/data/github_discovered_values.json"):
66 """Load discovered real filter values (e.g. issue numbers, run IDs) and
67 return them as a per-filter list. Appends to VALUE_ALTERNATES at import time."""
68 p = Path(path)
69 if not p.exists():
70 return
71 try:
72 data = json.loads(p.read_text())
73 except Exception:
74 return
75 if data.get("scope") and "FiscalMindset" not in data.get("scope", ""):
76 return # wrong scope
77 for filter_key, json_key in DISCOVERED_FILTERS.items():
78 vals = data.get(json_key, [])
79 if not vals:
80 continue
81 # values may be ints or strings; coerce to str
82 coerced = [str(v) for v in vals if v]
83 if not coerced:
84 continue
85 # discovered values beat hand-rolled alternates — put them first
86 existing = list(VALUE_ALTERNATES.get(filter_key, []))
87 merged = coerced + [v for v in existing if v not in coerced]
88 VALUE_ALTERNATES[filter_key] = merged[:20]
89 # also surface a couple extra useful mappings
90 if data.get("branches"):
91 VALUE_ALTERNATES["branch"] = list(dict.fromkeys(list(data["branches"]) + ["main"]))[:12]
92 if data.get("workflow_files"):
93 # store under workflow_file_name so table-specific alternates can use it
94 VALUE_ALTERNATES["workflow_file_name"] = list(data["workflow_files"])[:15]
95
96load_discovered_values()
97
98MAX_ROWS_RETURNED = 200
99
100def coral_version() -> str:
101 try:
102 out = subprocess.run(["coral", "--version"], capture_output=True, text=True, timeout=10)
103 return (out.stdout or out.stderr).strip().splitlines()[0] if out.returncode == 0 else "unknown"
104 except Exception:
105 return "unknown"
106
107def parse_md_table(out):
108 lines = [l.rstrip() for l in out.splitlines() if l.strip()]
109 header = None; rows = []
110 for ln in lines:
111 if ln.startswith("+"): continue
112 if ln.startswith("|") and ln.endswith("|"):
113 cells = [c.strip() for c in ln.strip("|").split("|")]
114 if not any(cells): continue
115 if header is None: header = cells; continue
116 if len(cells) != len(header) or sum(1 for c in cells if c) == 0: continue
117 rows.append(dict(zip(header, cells)))
118 return header, rows
119
120def run_coral_sql(query, workspace, rate_limit_retries=2, rate_limit_backoff=60):
121 """Run one coral sql query. If it hits a GitHub (secondary) rate limit (429),
122 wait `rate_limit_backoff` seconds and retry up to `rate_limit_retries` times so
123 transient throttling does not falsely fail a probe. Timeouts on a single call
124 are also retried once (big-list tables can exceed 60s on first slow call)."""
125 cmd = ["coral", "sql", "--workspace", workspace, query]
126 last = None
127 for attempt in range(rate_limit_retries + 1):
128 t0 = time.perf_counter()
129 try:
130 p = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
131 except subprocess.TimeoutExpired:
132 last = (-1, True, "timeout", [], None)
133 if attempt < rate_limit_retries:
134 time.sleep(2)
135 continue
136 wall = int((time.perf_counter() - t0) * 1000)
137 header, rows = parse_md_table(p.stdout)
138 is_err = p.returncode != 0 or "Error" in (p.stdout or "")[:200]
139 err_msg = ((p.stderr or "") + (p.stdout or ""))[:500] if is_err else None
140 if is_err and err_msg and "rate limit" in err_msg.lower() and attempt < rate_limit_retries:
141 time.sleep(rate_limit_backoff)
142 continue
143 return wall, is_err, err_msg, rows[:MAX_ROWS_RETURNED], header
144 return last if last else (0, True, "exhausted retries", [], None)
145
146def quote(v): return "'" + v.replace("'", "''") + "'"
147
148# Per-repo discovered (id_key -> value) maps. Loaded from
149# scripts/data/github_discovered_values.json: {repo_full_name: {id_key: [values]}}.
150_REPO_DISCOVERED = None # lazy-loaded by _build_combo_candidates
151
152def _build_combo_candidates(required):
153 """Return a list of {filter_key: value} dicts that pair owner+repo with a
154 per-repo ID. Each entry is a coherent tuple the install can actually see.
155 Falls back to single-filter alternates if no combos match."""
156 global _REPO_DISCOVERED
157 if _REPO_DISCOVERED is None:
158 _REPO_DISCOVERED = {}
159 p = Path("scripts/data/github_discovered_values.json")
160 if p.exists():
161 try:
162 data = json.loads(p.read_text())
163 except Exception:
164 data = None
165 if data:
166 # Hand-curated per-repo value mappings (from the discovery run).
167 # Only include IDs we actually verified come from that repo.
168 _REPO_DISCOVERED["FiscalMindset/Blindfold"] = {
169 "issue_number": [str(n) for n in data.get("issue_numbers", [])[:8]],
170 "pull_number": [str(n) for n in data.get("pr_numbers", [])[:8]],
171 "comment_id": [str(n) for n in data.get("comment_ids", [])[:3]],
172 "event_id": [str(n) for n in data.get("event_ids", [])[:5]],
173 "tag_name": data.get("tags", [])[:5],
174 "label_name": data.get("labels", [])[:5],
175 }
176 _REPO_DISCOVERED["FiscalMindset/coral"] = {
177 "run_id": [str(n) for n in data.get("workflow_runs", [])[:5]],
178 "check_run_id": [str(n) for n in data.get("check_run_ids", [])[:5]],
179 "artifact_id": [str(n) for n in data.get("artifact_ids", [])[:5]],
180 "job_id": [str(n) for n in data.get("job_ids", [])[:5]],
181 "commit_sha": data.get("commit_shas", [])[:3],
182 "environment_name": data.get("environments", [])[:3],
183 "branch": data.get("branches", [])[:5],
184 }
185 _REPO_DISCOVERED["FiscalMindset/coral_specs_testing"] = {
186 "tag_name": [r["tag"] for r in data.get("releases", []) if r.get("repo", "").endswith("coral_specs_testing")],
187 }
188 _REPO_DISCOVERED["FiscalMindset/opencode"] = {
189 "branch": ["main"] + data.get("branches", [])[:5],
190 }
191
192 # If the table's required filters include owner+repo+<id>, build tuples
193 # by joining repo-specific ID lists with the matching owner/repo pair.
194 has_owner = "owner" in required
195 has_repo = "repo" in required
196 if not (has_owner and has_repo):
197 return []
198 id_keys = [rf for rf in required if rf not in {"owner", "repo"}]
199 combos = []
200 for repo_full, repo_ids in _REPO_DISCOVERED.items():
201 owner, repo = repo_full.split("/", 1)
202 for ik in id_keys:
203 for id_val in repo_ids.get(ik, []):
204 c = {"owner": owner, "repo": repo, ik: id_val}
205 combos.append(c)
206 return combos[:30] # cap to keep discovery cheap
207
208def build_probes(source, table, required):
209 """Build probe variants, trying alternate candidate filter values so a
210 table passes if ANY real value set returns rows. Mirrors retry_batch.py's
211 intent but bakes value-alternation directly into the probe."""
212 candidate_maps = [dict(DEFAULT_FILTER_VALUES)]
213 for rf in required:
214 if rf in VALUE_ALTERNATES:
215 for alt in VALUE_ALTERNATES[rf]:
216 cand = dict(DEFAULT_FILTER_VALUES)
217 cand[rf] = alt
218 if cand not in candidate_maps:
219 candidate_maps.append(cand)
220
221 probes = []
222 seen_sql = set()
223 for idx, fmap in enumerate(candidate_maps):
224 fmap = {k: fmap.get(k, "1") for k in required}
225 where = " AND ".join(f"{k} = {quote(v)}" for k, v in fmap.items())
226 if not where:
227 continue # no required filters handled below
228 if idx == 0:
229 limits = [(1, "minimal"), (25, "realistic"), (200, "edge")]
230 else:
231 limits = [(1, f"alternate-{idx}")]
232 for limit, label in limits:
233 sql = f"SELECT * FROM {source}.{table} WHERE {where} LIMIT {limit}"
234 if sql in seen_sql:
235 continue
236 seen_sql.add(sql)
237 probes.append((label, sql, fmap, f"{label} probe"))
238 # No required filters: emit limit variants only
239 if not required:
240 for label, limit in [("minimal", 1), ("realistic", 25), ("edge", 200)]:
241 sql = f"SELECT * FROM {source}.{table} LIMIT {limit}"
242 if sql in seen_sql:
243 continue
244 seen_sql.add(sql)
245 probes.append((label, sql, {}, f"{label} probe (no filters)"))
246 return probes[:12]
247
248def run_table(workspace, source, table, required, runs, catalog_rec, prev_history):
249 table_full = f"{source}.{table}"
250 now_iso = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
251
252 # ---- Phase 1: discover a working filter-value set -----------------------
253 # 1) Try the default map first — if it returns ≥ 1 row, it's the winner
254 # (the common fast path, e.g. owner='anomalyco'+repo='opencode' succeeding immediately).
255 # 2) Only if the default returns 0 rows (or errors), probe alternate value maps.
256 # Exploration failures are NOT counted against the final verdict.
257 # IMPORTANT: "no error" is not "winning". Only ≥ 1 row counts as a win,
258 # so we don't lock in a default-value map that quietly returns 0 rows
259 # and then fail the canonical variants against it.
260 win_map = None
261 win_score = 0 # 0 is the "no winner found yet" sentinel
262 if required:
263 # Build combo-aware candidate maps. The discovered-values JSON groups real
264 # (owner, repo, id) tuples that the install can actually see (e.g.
265 # Blindfold + issue 54; coral + run 31300020216). A single-filter
266 # alternation can never find such combos, so we probe coherent tuples first.
267 combo_candidates = _build_combo_candidates(required)
268 default_map = dict(DEFAULT_FILTER_VALUES)
269 for rf in required:
270 default_map.setdefault(rf, "1")
271 default_map = {k: default_map.get(k, "1") for k in required}
272 # ---- Phase 1a: try coherent (owner, repo, id) combos -----------------
273 for combo in combo_candidates:
274 where = " AND ".join(f"{k} = {quote(v)}" for k, v in combo.items())
275 sql = f"SELECT * FROM {source}.{table} WHERE {where} LIMIT 1"
276 wall, is_err, err_msg, rows, _hdr = run_coral_sql(sql, workspace)
277 if not is_err and len(rows) >= 1:
278 win_map, win_score = dict(combo), len(rows)
279 break
280 # ---- Phase 1b: fall back to single-filter alternation if no combo won
281 if win_map is None:
282 where0 = " AND ".join(f"{k} = {quote(v)}" for k, v in default_map.items())
283 sql0 = f"SELECT * FROM {source}.{table} WHERE {where0} LIMIT 1"
284 wall0, is_err0, err0, rows0, _hdr0 = run_coral_sql(sql0, workspace)
285 if not is_err0 and len(rows0) >= 1:
286 win_map, win_score = dict(default_map), len(rows0)
287 else:
288 for rf in required:
289 for alt in VALUE_ALTERNATES.get(rf, []):
290 cand = dict(default_map)
291 cand[rf] = alt
292 where = " AND ".join(f"{k} = {quote(v)}" for k, v in cand.items())
293 sql = f"SELECT * FROM {source}.{table} WHERE {where} LIMIT 1"
294 wall, is_err, err_msg, rows, _hdr = run_coral_sql(sql, workspace)
295 score = (len(rows) if (not is_err and len(rows) >= 1) else -1)
296 if score > win_score:
297 win_score = score
298 win_map = dict(cand)
299 if win_map is not None:
300 break
301 if win_map is not None:
302 break
303 if win_map is None:
304 win_map = dict(default_map)
305 else:
306 win_map = {}
307
308 # ---- Phase 2: finalize on the discovered value set only -----------------
309 # Run the canonical minimal/realistic/edge variants against the winning map.
310 variants = []
311 if required:
312 where = " AND ".join(f"{k} = {quote(v)}" for k, v in win_map.items())
313 for limit, label in [(1, "minimal"), (25, "realistic"), (200, "edge")]:
314 sql = f"SELECT * FROM {source}.{table} WHERE {where} LIMIT {limit}"
315 variants.append((label, sql, dict(win_map), f"{label} probe"))
316 else:
317 for label, limit in [("minimal", 1), ("realistic", 25), ("edge", 200)]:
318 sql = f"SELECT * FROM {source}.{table} LIMIT {limit}"
319 variants.append((label, sql, {}, f"{label} probe (no filters)"))
320
321
322
323 if prev_history:
324 history = {
325 "first_run_at": prev_history.get("first_run_at"),
326 "last_retried_at": now_iso,
327 "retry_count": (prev_history.get("retry_count") or 0) + 1,
328 }
329 else:
330 history = {
331 "first_run_at": now_iso,
332 "last_retried_at": now_iso,
333 "retry_count": 0,
334 }
335
336 report = {
337 "table": table_full,
338 "schema": source,
339 "captured_at": now_iso,
340 "required_filters": required,
341 "guide": catalog_rec.get("guide"),
342 "description": catalog_rec.get("description"),
343 "probes": [],
344 "verdict": {"pass": None, "notes": None},
345 "discovery": {"winning_filters": win_map, "note": "winning filter-value set chosen by discovery probes"},
346 "history": history,
347 "metadata": {
348 "coral_version": coral_version(),
349 "probe_runner": f"probe_batch.py {runs}x",
350 "host": os.uname().nodename if hasattr(os, "uname") else "laptop-A",
351 },
352 }
353
354 for label, sql, args_used, intent in variants:
355 per = {"label": label, "sql": sql, "intent": intent, "args": args_used, "trials": []}
356 for trial in range(1, runs + 1):
357 wall, is_err, err_msg, rows, header = run_coral_sql(sql, workspace)
358 t_rec = {
359 "trial": trial, "wall_ms": wall, "is_error": is_err,
360 "row_count": len(rows),
361 "rows": rows,
362 "truncated": len(rows) > MAX_ROWS_RETURNED,
363 "columns": header,
364 "first_row": rows[0] if rows else None,
365 }
366 if err_msg and is_err:
367 t_rec["error"] = err_msg
368 per["trials"].append(t_rec)
369 kept = [t for t in per["trials"] if t["trial"] > 0]
370 if kept:
371 walls = [t["wall_ms"] for t in kept if t["wall_ms"] >= 0]
372 if walls:
373 per["latency_ms"] = {"min": min(walls), "median": int(statistics.median(walls)), "max": max(walls)}
374 per["error_count"] = sum(1 for t in kept if t["is_error"])
375 per["row_counts"] = [t["row_count"] for t in kept]
376 report["probes"].append(per)
377
378 errors = sum(p.get("error_count", 0) for p in report["probes"])
379 rows_ok = sum(1 for p in report["probes"] if any(t["row_count"] > 0 for t in p["trials"]))
380 if errors == 0 and rows_ok >= 2:
381 report["verdict"]["pass"] = True
382 report["verdict"]["notes"] = f"All variants returned rows on ≥2 trials, 0 errors."
383 elif errors > 0 and rows_ok > 0:
384 report["verdict"]["pass"] = "partial"
385 report["verdict"]["notes"] = f"{errors} errors across trials but {rows_ok} variants returned data."
386 else:
387 report["verdict"]["pass"] = False
388 report["verdict"]["notes"] = f"All variants failed: {errors} errors, {rows_ok} successful."
389 return report
390
391def main():
392 ap = argparse.ArgumentParser()
393 ap.add_argument("--source", required=True)
394 ap.add_argument("--only", default=None)
395 ap.add_argument("--skip-done", action="store_true")
396 ap.add_argument("--workers", type=int, default=4)
397 ap.add_argument("--runs", type=int, default=2)
398 ap.add_argument("--workspace", default=os.environ.get("CORAL_WORKSPACE", "default"))
399 args = ap.parse_args()
400
401 cat = json.loads(Path(f"reports/{args.source}/catalog.json").read_text())
402 cat_map = {t["name"]: t for t in cat["tables"]}
403 tables = list(cat_map.keys())
404 if args.only:
405 only = set(args.only.split(","))
406 tables = [t for t in tables if t in only]
407 if args.skip_done:
408 done = Path(f"reports/{args.source}/tables")
409 tables = [t for t in tables if not (done / f"{t}.json").exists()]
410
411 print(f"probing {len(tables)} tables (in-process, workers={args.workers})", file=sys.stderr)
412
413 def worker(table):
414 rec_cat = cat_map[table]
415 required = rec_cat.get("required_filters", [])
416 # Load previous history if file exists
417 fp = Path(f"reports/{args.source}/tables/{table}.json")
418 prev_history = None
419 if fp.exists():
420 try:
421 prev_history = json.loads(fp.read_text()).get("history")
422 except Exception:
423 pass
424 rep = run_table(args.workspace, args.source, table, required, args.runs, rec_cat, prev_history)
425 fp.parent.mkdir(parents=True, exist_ok=True)
426 fp.write_text(json.dumps(rep, indent=2, default=str) + "\n")
427 # P2 / new feature: also archive this run to tables/<name>.history/<ISO>.json
428 # so users can compare versions over time. The canonical JSON stays the latest;
429 # the history directory is append-only.
430 try:
431 hist_dir = Path(f"reports/{args.source}/tables/{table}.history")
432 hist_dir.mkdir(parents=True, exist_ok=True)
433 ts = rep["captured_at"].replace(":", "-").replace(".", "-")
434 (hist_dir / f"{ts}.json").write_text(json.dumps(rep, indent=2, default=str) + "\n")
435 except Exception as e:
436 print(f"warn: could not archive history for {table}: {e}", file=sys.stderr)
437 return table, rep["verdict"]["pass"]
438
439 ok = 0
440 with ThreadPoolExecutor(max_workers=args.workers) as ex:
441 futs = [ex.submit(worker, t) for t in tables]
442 for i, fut in enumerate(as_completed(futs)):
443 try:
444 table, verdict = fut.result()
445 marker = "✓" if verdict is True else ("~" if verdict == "partial" else "✗")
446 print(f"{marker} [{i+1}/{len(tables)}] {table}: verdict={verdict}", file=sys.stderr)
447 if verdict is True: ok += 1
448 except Exception as e:
449 print(f"✗ exception: {e}", file=sys.stderr)
450
451 print(f"\n{ok}/{len(tables)} tables pass", file=sys.stderr)
452
453if __name__ == "__main__":
454 main()

reprobe_github.py

v1.0.0

Version-preserving targeted re-probe of github tables. Selects a table set (--all / --failing / --set), optionally refreshes the token, and hands off to probe_batch.py.

/opt/render/project/src/scripts/reprobe_github.py

1#!/usr/bin/env python3
2"""Version-preserving re-probe of github tables using the expanded GitHub App token.
3
4Why this exists
5---------------
6A full github re-probe (364 tables) is expensive and long. This runner lets you
7re-probe a **targeted set** of tables (by name, or only the currently failing /
8partial ones) while keeping the coral source token fresh and preserving version
9history (each prior result is archived to `tables/<name>.history/` by probe_batch).
10
11Versioning / spec
12-----------------
13- Version: 1.0.0
14- Conventions: writes canonical JSON to `reports/github/tables/<name>.json`
15 (latest wins) and appends each prior run to `reports/github/tables/<name>.history/`
16 (append-only, version comparison). The Next.js `/report` surface renders the
17 `coverage_pct`, `snapshots.json`, and the .history file count.
18- Does NOT delete any existing report data.
19
20Selection
21---------
22 --all re-probe every table (canonical + history)
23 --failing only tables whose verdict is not True (incl partial)
24 --include-partial include partial verdicts (default excludes them)
25 --set=a,b,c explicit comma list of tables
26 --category=RATE_LIMIT only tables whose last error matches a classifier tag
27 (see scripts/analyze_failures.py for tag names)
28
29Usage
30-----
31 python3 scripts/reprobe_github.py --failing --include-partial --workers 3
32 python3 scripts/reprobe_github.py --set=contents,issues,labels --workers 3
33 python3 scripts/reprobe_github.py --all --workers 4
34
35Rate-limits
36-----------
37`probe_batch.py` now retries 429 rate-limit errors with backoff, so transient
38GitHub secondary throttling does not falsely fail a probe.
39"""
40import argparse, json, glob, os, subprocess, sys
41from pathlib import Path
42
43REPO = Path(__file__).resolve().parent.parent
44VERSION = "1.0.0"
45
46def target_tables(selection, include_partial, all_tables):
47 tables_dir = REPO / "reports/github/tables"
48 if all_tables:
49 return sorted(Path(f).stem for f in glob.glob(str(tables_dir / "*.json")))
50 if selection:
51 sel = set(selection)
52 return sorted(t for t in sel if (tables_dir / f"{t}.json").exists())
53 out = []
54 for f in glob.glob(str(tables_dir / "*.json")):
55 d = json.load(open(f))
56 v = d.get("verdict", {})
57 vp = v.get("pass") if isinstance(v, dict) else v
58 if vp is True:
59 continue
60 if vp == "partial" and not include_partial:
61 continue
62 out.append(Path(f).stem)
63 return sorted(out)
64
65def main():
66 ap = argparse.ArgumentParser(description="Version-preserving targeted github re-probe")
67 g = ap.add_mutually_exclusive_group()
68 g.add_argument("--all", action="store_true")
69 g.add_argument("--failing", action="store_true")
70 g.add_argument("--set", default="")
71 ap.add_argument("--include-partial", action="store_true")
72 ap.add_argument("--workers", type=int, default=3)
73 ap.add_argument("--runs", type=int, default=1)
74 ap.add_argument("--refresh-token", action="store_true",
75 help="refresh the github install token before probing (uses GITHUB_APP_* env)")
76 args = ap.parse_args()
77
78 if args.refresh_token:
79 r = subprocess.run([sys.executable, str(REPO / "scripts/refresh_github_token.py")],
80 cwd=str(REPO))
81 if r.returncode != 0:
82 print("token refresh failed", file=sys.stderr); sys.exit(1)
83
84 if args.set:
85 selection = [s for s in args.set.split(",") if s]
86 else:
87 selection = None
88 tables = target_tables(selection, args.include_partial, args.all)
89 if not tables:
90 print("no tables matched", file=sys.stderr); sys.exit(0)
91 print(f"[reprobe_github {VERSION}] re-probing {len(tables)} tables", file=sys.stderr)
92
93 # Ensure GITHUB_TOKEN is present in env (coral source may already be installed)
94 env = dict(os.environ)
95 argv = ["python3", str(REPO / "scripts/probe_batch.py"), "--source", "github",
96 "--runs", str(args.runs), "--workers", str(args.workers), "--only", ",".join(tables)]
97 r = subprocess.run(argv, cwd=str(REPO), env=env, text=True)
98 sys.exit(r.returncode)
99
100if __name__ == "__main__":
101 main()
102

refresh_github_token.py

v1.0.0

Refreshes the GitHub App installation access token and reinstalls the coral github source, so long probe runs never expire mid-batch.

/opt/render/project/src/scripts/refresh_github_token.py

1#!/usr/bin/env python3
2"""Refresh the coral github source's GitHub App installation token and reinstall it.
3
4Why this exists
5---------------
6The repo probes `github` tables through Coral's bundled source, which authenticates
7with a single `GITHUB_TOKEN`. The highest-budget credential available is a GitHub
8App **installation access token** (ghs_), which the app owner regenerates from the
9app's private key + App ID + installation ID. These tokens live only ~1 hour, so a
10long probe run needs them refreshed before expiry.
11
12This script:
13 1. Signs an App JWT (RS256) from the app private key.
14 2. POSTs to create a fresh installation access token.
15 3. Re-runs `coral source remove github` + `coral source add github` with that token.
16
17Versioning
18----------
19- Version: 1.0.0
20- Requires: the app private key PEM (path via --pem), App ID (--app-id),
21 installation ID (--installation). Kept OUT of git (secrets).
22- The refresh is idempotent and safe to call repeatedly.
23
24Usage
25-----
26 GITHUB_APP_PEM=/path/to/private-key.pem \
27 GITHUB_APP_ID=4783650 \
28 GITHUB_APP_INSTALLATION=158026446 \
29 python3 scripts/refresh_github_token.py
30
31 # or with flags:
32 python3 scripts/refresh_github_token.py \
33 --pem /path/private-key.pem --app-id 4783650 --installation 158026446
34
35Outputs
36-------
37Prints `coral reloaded, token <prefix> len <n>` and the coral `source add` summary.
38"""
39import argparse, base64, json, os, subprocess, sys, time
40
41VERSION = "1.0.0"
42
43def b64url(data: bytes) -> str:
44 return base64.urlsafe_b64encode(data).rstrip(b"=").decode()
45
46def make_app_jwt(app_id: int, pem_path: str) -> str:
47 """Sign a GitHub App JWT (RS256) valid for ~9 minutes."""
48 now = int(time.time())
49 header = b64url(json.dumps({"alg": "RS256", "typ": "JWT"}).encode())
50 payload = b64url(json.dumps({"iat": now - 30, "exp": now + 540, "iss": str(app_id)}).encode())
51 signing_input = f"{header}.{payload}"
52 sig = subprocess.run(
53 ["openssl", "dgst", "-sha256", "-sign", pem_path],
54 input=signing_input.encode(), capture_output=True,
55 )
56 if sig.returncode != 0:
57 raise RuntimeError(f"openssl signing failed: {sig.stderr.decode()}")
58 return f"{signing_input}.{b64url(sig.stdout)}"
59
60def fresh_installation_token(app_id: int, pem_path: str, installation: int) -> str:
61 jwt = make_app_jwt(app_id, pem_path)
62 curl = subprocess.run(
63 ["curl", "-s", "-X", "POST",
64 "-H", f"Authorization: Bearer {jwt}",
65 "-H", "Accept: application/vnd.github+json",
66 f"https://api.github.com/app/installations/{installation}/access_tokens"],
67 capture_output=True, text=True,
68 )
69 d = json.loads(curl.stdout)
70 token = d.get("token")
71 if not token:
72 raise RuntimeError(f"no installation token in response: {json.dumps(d)[:300]}")
73 return token
74
75def reload_coral_token(source: str, token: str) -> subprocess.CompletedProcess:
76 env = dict(os.environ, GITHUB_TOKEN=token)
77 subprocess.run(["coral", "source", "remove", source], env=env, capture_output=True)
78 return subprocess.run(["coral", "source", "add", source], env=env, capture_output=True, text=True)
79
80def main():
81 ap = argparse.ArgumentParser(description="Refresh coral github source installation token")
82 ap.add_argument("--pem", default=os.environ.get("GITHUB_APP_PEM"))
83 ap.add_argument("--app-id", type=int, default=int(os.environ.get("GITHUB_APP_ID", "0")))
84 ap.add_argument("--installation", type=int, default=int(os.environ.get("GITHUB_APP_INSTALLATION", "0")))
85 ap.add_argument("--source", default="github")
86 ap.add_argument("--print-token", action="store_true", help="also write token to ./_gh_token (gitignored)")
87 args = ap.parse_args()
88 if not args.pem or not args.app_id or not args.installation:
89 print("ERR: --pem, --app-id, --installation are required (or set GITHUB_APP_* env)", file=sys.stderr)
90 sys.exit(1)
91 token = fresh_installation_token(args.app_id, args.pem, args.installation)
92 r = reload_coral_token(args.source, token)
93 if r.returncode != 0:
94 print("ERR coral source add:\n" + r.stderr[-1000:], file=sys.stderr)
95 sys.exit(1)
96 if args.print_token:
97 with open("_gh_token", "w") as f:
98 f.write(token)
99 print(f"coral reloaded ({args.source}), token {token[:4]} len {len(token)} ({VERSION})")
100
101if __name__ == "__main__":
102 main()
103

retry_batch.py

Retries previously-failed tables classified as retryable, trying alternate filter values (anomalyco, sst / opencode, linux, Hello-World).

/opt/render/project/src/scripts/retry_batch.py

1#!/usr/bin/env python3
2"""Retry previously-failed probes with rate-limit-aware timing.
3
4For each failure:
5- If category is upstream.not_found (404) on owner=anomalyco, repo=opencode
6 → try alternates (sst, opencode-ai, octocat) using fast batch.
7- If upstream.rate_limit → wait 5s then retry once.
8- Otherwise (coral_bug, auth, etc.) → record and skip.
9
10Usage:
11 python3 scripts/retry_batch.py --source github [--workers 4]
12"""
13import argparse, json, os, re, subprocess, sys, time
14from concurrent.futures import ThreadPoolExecutor, as_completed
15from pathlib import Path
16
17# Best default filter values that work for many github tables
18ALT_OWNER = "anomalyco"
19ALT_REPO = "opencode"
20ALT_ORG = "opencode"
21ALT_USER = "anomalyco"
22
23DEFAULT_FILTER_VALUES = {
24 "owner": ALT_OWNER, "repo": ALT_REPO, "org": ALT_ORG, "username": ALT_USER,
25 "enterprise": "github", "plan_id": "1", "assignment_id": "1", "app_slug": "opencode",
26 "gist_id": "1", "subject_digest": "sha256:0000",
27 "branch": "main", "ref": "main", "issue_number": "1",
28 "pull_number": "1", "alert_number": "1", "attempt_number": "1",
29 "run_id": "1", "check_run_id": "1", "hook_id": "1",
30 "runner_group_id": "1", "environment_name": "production",
31 "commit_sha": "main", "repository_id": "1296269",
32 "file_sha": "main", "tag_name": "v1", "build_id": "1",
33 "analysis_id": "1", "sarif_id": "1", "delivery_id": "1",
34 "deployment_id": "1", "job_id": "1", "secret_name": "1",
35 "variable_name": "1", "key": "1", "page": "1",
36 "installation_id": "1", "rule_id": "1", "rule_suite_id": "1",
37}
38
39# Categories we will RETRY
40RETRYABLE = {
41 "upstream.not_found",
42 "upstream.rate_limit",
43 "upstream.unprocessable",
44 "upstream.server_error",
45 "protocol.decode_failed",
46 "protocol.empty_response",
47 "unknown.no_error_msg",
48 "unknown.unclassified",
49 "unknown.other",
50}
51
52# Categories we skip entirely
53SKIP_CATEGORIES = {
54 "coral_bug.table_missing", "coral_bug.column_missing", "coral_bug.column_missing_alt",
55 "coral_bug.required_filter", "coral_bug.named_args", "coral_bug.unsupported_arg",
56 "coral_bug.invalid_input",
57 "auth.app_jwt_required", "auth.jwt_decode_failed",
58 "upstream.gone", "upstream.bad_request", "upstream.forbidden",
59}
60
61def quote(v): return "'" + v.replace("'", "''") + "'"
62
63def parse_md_table(out):
64 lines = [l.rstrip() for l in out.splitlines() if l.strip()]
65 header = None; rows = []
66 for ln in lines:
67 if ln.startswith("+"): continue
68 if ln.startswith("|") and ln.endswith("|"):
69 cells = [c.strip() for c in ln.strip("|").split("|")]
70 if not any(cells): continue
71 if header is None: header = cells; continue
72 if len(cells) != len(header) or sum(1 for c in cells if c) == 0: continue
73 rows.append(dict(zip(header, cells)))
74 return header, rows
75
76def run_sql(query, workspace, timeout=60, retry_on_rate_limit=True):
77 cmd = ["coral", "sql", "--workspace", workspace, query]
78 for attempt in range(2):
79 t0 = time.perf_counter()
80 try:
81 p = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
82 except subprocess.TimeoutExpired:
83 return -1, True, "timeout", 0, None
84 wall = int((time.perf_counter() - t0) * 1000)
85 header, rows = parse_md_table(p.stdout)
86 is_err = p.returncode != 0 or "Error" in (p.stdout or "")[:200]
87 err_msg = ((p.stderr or "") + (p.stdout or ""))[:500] if is_err else None
88 if (not is_err) or (not retry_on_rate_limit):
89 return wall, is_err, err_msg, len(rows), header
90 if "rate limit" in (err_msg or "").lower() and attempt == 0:
91 # Wait then retry once
92 time.sleep(30)
93 continue
94 return wall, is_err, err_msg, len(rows), header
95 return wall, True, err_msg, 0, header
96
97def classify(err):
98 if not err: return "unknown.no_error_msg"
99 pat = [
100 ("upstream.rate_limit", r"Source rate limit exceeded \(429\)"),
101 ("upstream.not_found", r"Source resource was not found \(404\)"),
102 ("upstream.unprocessable", r"Source request failed \(422\)"),
103 ("upstream.server_error", r"Source server error \(5\d\d\)"),
104 ("auth.app_jwt_required", r"Source authentication failed \(401\)"),
105 ("auth.jwt_decode_failed", r"A JSON web token could not be decoded"),
106 ("protocol.decode_failed", r"source (api )?response decode failed"),
107 ("protocol.empty_response", r"eof while parsing"),
108 ("upstream.gone", r"Source request failed \(410\)"),
109 ("upstream.bad_request", r"Source rejected the request \(400\)"),
110 ("upstream.forbidden", r"Source request failed \(403\)"),
111 ("coral_bug.table_missing", r"Table `[^`]+` not found"),
112 ("coral_bug.column_missing", r"No column named `[^`]+`"),
113 ("coral_bug.required_filter", r"requires a constant equality filter"),
114 ("coral_bug.named_args", r"requires named arguments"),
115 ("coral_bug.unsupported_arg", r"Unsupported function argument type"),
116 ("coral_bug.invalid_input", r"invalid input:"),
117 ]
118 for label, p in pat:
119 if re.search(p, err, re.IGNORECASE): return label
120 return "unknown.other"
121
122def retry_table(workspace, table, required, current_err, current_alt_value=None):
123 """Try alternate filter values for one table. Return (success, new_err, new_fmap, attempts)."""
124 # Build candidate filter sets
125 candidates = []
126 if required:
127 # Take current default
128 base = {rf: DEFAULT_FILTER_VALUES.get(rf, "1") for rf in required}
129 candidates.append(base.copy())
130 # Try alternating owner
131 for alt_o in [ALT_OWNER, "sst", "opencode-ai", "octocat"]:
132 for alt_r in ["opencode", "linux", "Hello-World"]:
133 cand = base.copy()
134 if "owner" in cand: cand["owner"] = alt_o
135 if "repo" in cand: cand["repo"] = alt_r
136 if "username" in cand: cand["username"] = alt_o
137 if "org" in cand: cand["org"] = alt_o
138 if cand != base and cand not in candidates:
139 candidates.append(cand)
140 # No-filter tables: just retry with different limits
141 if not required:
142 return False, current_err, {}, 0
143
144 for i, fmap in enumerate(candidates[:8]):
145 where = " AND ".join(f"{k} = {quote(v)}" for k, v in fmap.items())
146 sql = f"SELECT * FROM github.{table} WHERE {where} LIMIT 5"
147 wall, is_err, err_msg, n_rows, _ = run_sql(sql, workspace)
148 if not is_err and n_rows > 0:
149 return True, None, fmap, i + 1
150 return False, current_err, {}, len(candidates[:8])
151
152def main():
153 ap = argparse.ArgumentParser()
154 ap.add_argument("--source", required=True)
155 ap.add_argument("--workers", type=int, default=4)
156 ap.add_argument("--only-category", default=None, help="only retry tables in this error category")
157 ap.add_argument("--workspace", default=os.environ.get("CORAL_WORKSPACE", "default"))
158 args = ap.parse_args()
159
160 analysis = json.loads(Path(f"reports/{args.source}/analysis.json").read_text())
161 catalog = json.loads(Path(f"reports/{args.source}/catalog.json").read_text())
162
163 retry_targets = []
164 for tname, info in analysis["per_table"].items():
165 if info["verdict"] is True: continue
166 first_cat = info["failures"][0]["category"] if info["failures"] else None
167 if not first_cat: continue
168 if first_cat in SKIP_CATEGORIES: continue
169 if args.only_category and first_cat != args.only_category: continue
170 short = tname.split(".",1)[1]
171 rec = next((t for t in catalog["tables"] if t["name"] == short), None)
172 if not rec: continue
173 if not rec.get("required_filters"): continue # skip no-filter
174 retry_targets.append((short, rec["required_filters"], info["failures"][0].get("error", "")))
175
176 print(f"retrying {len(retry_targets)} tables", file=sys.stderr)
177
178 def worker(t):
179 short, req, err = t
180 ok, new_err, fmap, attempts = retry_table(args.workspace, short, req, err)
181 return short, ok, new_err, fmap, attempts
182
183 successes = 0
184 failures = []
185 with ThreadPoolExecutor(max_workers=args.workers) as ex:
186 futs = {ex.submit(worker, t): t for t in retry_targets}
187 for i, fut in enumerate(as_completed(futs)):
188 short, ok, new_err, fmap, attempts = fut.result()
189 if ok:
190 successes += 1
191 # Update report
192 jf = Path(f"reports/{args.source}/tables/{short}.json")
193 if jf.exists():
194 rec = json.loads(jf.read_text())
195 rec["verdict"] = {"pass": True, "notes": f"Retry succeeded after {attempts} attempts with {fmap}"}
196 rec["retried_filters"] = fmap
197 jf.write_text(json.dumps(rec, indent=2) + "\n")
198 print(f"✓ [{i+1}/{len(retry_targets)}] {short}: retry worked with {fmap}", file=sys.stderr)
199 else:
200 failures.append(short)
201 print(f"✗ [{i+1}/{len(retry_targets)}] {short}: still failing ({attempts} attempts)", file=sys.stderr)
202
203 print(f"\n{successes} improved, {len(failures)} still failing", file=sys.stderr)
204
205if __name__ == "__main__":
206 main()