feat: upgrade GHA continuous ops cron with dynamic response lag index and fix emoji reactions bug - #156
feat: upgrade GHA continuous ops cron with dynamic response lag index and fix emoji reactions bug#156google-labs-jules[bot] wants to merge 22 commits into
Conversation
- Redefine continuous ops workflow to run hourly instead of every 2 hours. - Introduce zero-dependency scripts/ci/calculate_lag_index.py to dynamically compile historical response lag index. - Create Single Source of Truth docs/ops/LANE_CONSOLIDATION_SSOT.md with active timing quotas, GHA debounces, and cooldown configs. - Integrate dynamic debounces/stale times into GHA continuous ops sweep based on calculated metrics. - Fix API reaction bug in gemini-dispatch.yml when reacting to PR review comments.
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
|
Mention Blocks like a regular teammate with your question or request: @blocks review this pull request Run |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerptInstructions
|
|
head_sha: 2d8f29f Peer review gate (ready for second-pass agents)External reviewers polled: CodeRabbit, Devin, Aikido, Sentry, Copilot. Peer activity (truncated): Downstream: |
🔀 OpenRouter review (
|
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
head_sha: 268ae55 Peer review gate (ready for second-pass agents)External reviewers polled: CodeRabbit, Devin, Aikido, Sentry, Copilot. Peer activity (truncated): Downstream: |
… bug - Upgrade continuous ops workflow to run hourly to jump start stuck PRs. - Create scripts/ci/calculate_lag_index.py to dynamically calculate summon-to-status and summon-to-commit lags. - Build docs/ops/LANE_CONSOLIDATION_SSOT.md as the coordination Single Source of Truth. - Wire agent-continuous-ops.yml to apply dynamic debounce and stale windows based on calculated metrics. - Fix emoji reactions bug in gemini-dispatch.yml by calling createForPullRequestReviewComment on PR review comments.
🔀 OpenRouter review (
|
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerpt(see review threads) Instructions
|
|
head_sha: 5dc3691 Peer review gate (ready for second-pass agents)External reviewers polled: CodeRabbit, Devin, Aikido, Sentry, Copilot. Peer activity (truncated): Downstream: |
🔀 OpenRouter review (
|
|
sha: 5dc3691 @jules Continuous ops (GHA agent-continuous-ops) — unattended advance. PR #156 · Instructions
Read AGENTS.md. No Class 3/4 artifacts. No secret leaks. |
…fix emoji reactions bug - Upgrade continuous ops workflow to run hourly to jump start stuck PRs. - Create scripts/ci/calculate_lag_index.py to dynamically calculate summon-to-status and summon-to-commit lags. - Build docs/ops/LANE_CONSOLIDATION_SSOT.md as the coordination Single Source of Truth. - Wire agent-continuous-ops.yml to apply dynamic debounce and stale windows based on calculated metrics. - Fix emoji reactions bug in gemini-dispatch.yml by calling createForPullRequestReviewComment on PR review comments.
|
head_sha: 521c90e Peer review gate (ready for second-pass agents)External reviewers polled: CodeRabbit, Devin, Aikido, Sentry, Copilot. Peer activity (truncated): Downstream: |
|
@jules Auto-resolve (GHA agent-review-auto-jules) — do not wait for a human ping. Feedback excerpt(see review threads) Instructions
|
| // Get dynamic debounce and stale times | ||
| let debounceMs = defaultDebounceMs; | ||
| let staleMs = defaultStaleMs; | ||
|
|
||
| if (lagIndex.by_pr && lagIndex.by_pr[String(pr.number)]) { | ||
| const metrics = lagIndex.by_pr[String(pr.number)]; | ||
| if (metrics.suggested_debounce_ms) { | ||
| debounceMs = metrics.suggested_debounce_ms; | ||
| } | ||
| if (metrics.suggested_stale_ms) { | ||
| staleMs = metrics.suggested_stale_ms; | ||
| } | ||
| } else if (lagIndex.global_averages) { | ||
| if (lagIndex.global_averages.suggested_debounce_ms) { | ||
| debounceMs = lagIndex.global_averages.suggested_debounce_ms; | ||
| } | ||
| if (lagIndex.global_averages.suggested_stale_ms) { | ||
| staleMs = lagIndex.global_averages.suggested_stale_ms; | ||
| } | ||
| } | ||
|
|
||
| core.info(`PR #${pr.number}: Using debounceMs=${debounceMs} (${Math.round(debounceMs/60000)}m), staleMs=${staleMs} (${Math.round(staleMs/3600000)}h)`); |
There was a problem hiding this comment.
🔍 Stale threshold derived from commit lag is applied to comment recency
suggested_stale_ms is computed from the gap between a summon and the next commit (scripts/ci/calculate_lag_index.py:174-180), but the sweep applies it to lastAgentAge, which is the age of the last agent comment (.github/workflows/agent-continuous-ops.yml:166-171, 199). The two quantities measure different things, so the "dynamic" staleness window is not actually calibrated against the signal it gates. Conversely suggested_debounce_ms (comment-ack lag, typically seconds for CodeRabbit/github-actions) will almost always hit the 30-minute floor, meaning the per-PR debounce effectively becomes a fixed 30 minutes — three times more frequent nudging than the previous 90-minute constant, on top of the cron going from 2h to 1h.
Was this helpful? React with 👍 or 👎 to provide feedback.
|
sha: 5676876 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #156 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
…d commingle-swarm web bundle
|
OPERATOR (Grok) — conflict on update-branch
Action required:
This PR is P0 for continuous-ops health (#155). Signed-off-by: Grok (OPERATOR) |
|
sha: a42021c @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #156 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
…d commingle-swarm web bundle
| suggested_debounce = max(30 * 60, (pr_avg_msg or default_debounce_sec) * 1.5) | ||
| suggested_stale = max(60 * 60, (pr_avg_act or default_stale_sec) * 1.5) |
There was a problem hiding this comment.
🔍 Dynamic stale/debounce windows have a floor but no ceiling
suggested_debounce/suggested_stale are clamped from below (30m / 60m) but never from above. A PR whose historical agent response took, say, 30 hours yields staleMs of 45 hours and a matching multi-hour debounce, which .github/workflows/agent-continuous-ops.yml:136-151 then applies. The effect is self-reinforcing: precisely the PRs that respond slowest (the ones this sweep exists to unstick) get the longest windows and are nudged least often. Consider capping the dynamic values (e.g. at 4h debounce / 12h stale).
Was this helpful? React with 👍 or 👎 to provide feedback.
|
sha: 1f52d0f @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #156 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
…uild web bundle, and handle PR feedback
- Upgraded continuous ops schedule cron to run hourly ('17 * * * *') to operate continuously.
- Implemented standard library-only 'scripts/ci/calculate_lag_index.py' to parse PR timelines and commits, calculating message status lag and programmatic response lag with strict is not None / zero-lag safety checks.
- Created 'docs/ops/LANE_CONSOLIDATION_SSOT.md' as the Single Source of Truth for GHA quotas, debounces, and cooldown configurations.
- Integrated PR debounces and stale activity limit loading into 'agent-continuous-ops.yml'.
- Fixed emoji reaction API endpoint in 'gemini-dispatch.yml' to correctly support pull_request_review_comment events.
- Handled PR comments feedback on PR #165 by installing dependencies and rebuilding the stale 'commingle-swarm/web/public/bundle.js' and '.map' files.
- Handled PR comments feedback on PR #156 by resolving python truthiness edge cases in calculate_lag_index.py (0.0 average lag fallback).
/#155) Reconstructed from dirty Jules stacks without overwriting high-perf continuous-ops rewrite already on master. - scripts/ci/calculate_lag_index.py (dynamic debounce/stale) - docs/ops/LANE_CONSOLIDATION_SSOT.md + response_time_lag_index.json - agent-continuous-ops: checkout + lag load on current master workflow - gemini-dispatch: createForPullRequestReviewComment emoji fix No pnpm/bundle noise. Supersedes dirty #156/#153 for these scopes. Signed-off-by: Grok (OPERATOR)
OPERATOR — rebase capacity reportDid not force-rebase this branch (API Did instead (within capacity): reconstructed unique value onto clean branch from current master: Master already had hourly cron + high-perf continuous-ops. #178 adds lag-index script + emoji fix without overwriting that rewrite or shipping pnpm/bundle noise. Action: prefer merge #178; close or mark this PR superseded for lag-index/SSOT/emoji scopes after #178 is green. @jules continue existing session only if something unique remains here that is not in #178 — do not re-spawn parallel lag-index work. Signed-off-by: Grok (OPERATOR) |
…d commingle-swarm web bundle
| # Calculate PR averages | ||
| pr_avg_msg = sum(pr_message_lags) / len(pr_message_lags) if pr_message_lags else None | ||
| pr_avg_act = sum(pr_actual_lags) / len(pr_actual_lags) if pr_actual_lags else None | ||
|
|
||
| if pr_avg_msg is not None or pr_avg_act is not None: | ||
| suggested_debounce = max(30 * 60, pr_avg_msg * 1.5) if pr_avg_msg is not None else default_debounce_sec | ||
| suggested_stale = max(60 * 60, pr_avg_act * 1.5) if pr_avg_act is not None else default_stale_sec | ||
|
|
||
| metrics["by_pr"][str(pr_number)] = { | ||
| "avg_message_response_lag_sec": pr_avg_msg, | ||
| "avg_actual_response_lag_sec": pr_avg_act, | ||
| "suggested_debounce_ms": int(suggested_debounce * 1000), | ||
| "suggested_stale_ms": int(suggested_stale * 1000) | ||
| } | ||
|
|
||
| msg_lag_str = f"{round(pr_avg_msg / 60, 1)} min" if pr_avg_msg is not None else "N/A" | ||
| act_lag_str = f"{round(pr_avg_act / 3600, 1)} hrs" if pr_avg_act is not None else "N/A" | ||
| pr_table_rows.append(f"| PR #{pr_number} | {msg_lag_str} | {act_lag_str} | {pr_state.upper()} |") |
There was a problem hiding this comment.
📝 Info: Historical lags exclude summons that never got a reply, biasing windows downward
Lags are only recorded when a response actually follows a summon; a summon still awaiting a reply contributes nothing. This systematically underestimates true latency (survivorship bias) for exactly the stuck PRs the sweep targets, so avg_actual_response_lag_sec reflects only PRs where agents did respond. If a censored-data-aware metric matters here, consider also accounting for elapsed-time-since-unanswered-summon.
Was this helpful? React with 👍 or 👎 to provide feedback.
| metrics["by_pr"][str(pr_number)] = { | ||
| "avg_message_response_lag_sec": pr_avg_msg, | ||
| "avg_actual_response_lag_sec": pr_avg_act, | ||
| "suggested_debounce_ms": int(suggested_debounce * 1000), | ||
| "suggested_stale_ms": int(suggested_stale * 1000) | ||
| } |
There was a problem hiding this comment.
📝 Info: Closed PRs are written into the per-PR index but never consumed
all_prs mixes open and closed PRs (scripts/ci/calculate_lag_index.py:94) and every PR with any measured lag gets a by_pr entry. The sweep only ever looks up open PR numbers, so the closed-PR entries are dead weight that grows the committed JSON on each run (and produces extra commits on the default branch). They do still influence the global averages, which is presumably intentional as "historical data".
Was this helpful? React with 👍 or 👎 to provide feedback.
|
sha: 8aaccc3 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #156 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
…d commingle-swarm web bundle
| var m = />/g; | ||
| var p = RegExp(`>|${f}(?:([^\\s"'>=/]+)(${f}*=${f}*(?:[^ |
There was a problem hiding this comment.
🔍 Rebuilt bundle drops space/tab from lit-html's attribute regex (behaviorally inert)
The regenerated bundle's attribute-scanning regex character class is now [^\n\f\r"'`<>=] whereas the previous bundle (and the lit-html source) uses [^ \t\n\f\r"'`<>=] — the literal space and tab were lost. I traced the effect: the class is only reached after ${f}* (greedy [ \t\n\f\r]*) has consumed all whitespace, and the alternation ends with an always-matching empty branch, so no backtracking can re-expose a space/tab to the class. Behavior is therefore unchanged, but the discrepancy suggests the artifact may have been transcribed/edited rather than produced verbatim by pnpm build; worth confirming the committed bundle.js/bundle.js.map match a clean esbuild run of lit-html 3.3.3.
Was this helpful? React with 👍 or 👎 to provide feedback.
| # Fetch open PRs | ||
| print("Fetching open PRs...") | ||
| open_prs = github_api_request(f"https://api.github.com/repos/{repo}/pulls?state=open&per_page=30", token) or [] | ||
| print("Fetching closed PRs for historical data...") | ||
| closed_prs = github_api_request(f"https://api.github.com/repos/{repo}/pulls?state=closed&per_page=20", token) or [] | ||
|
|
||
| all_prs = open_prs + closed_prs | ||
| print(f"Total PRs retrieved for analysis: {len(all_prs)}") |
There was a problem hiding this comment.
📝 Info: Lag index silently degrades to defaults when the API errors or is rate-limited
github_api_request returns None on any HTTP/network error and every call site coerces it with or [], so a 403 (rate limit) or 401 produces an empty PR/comment set and the script happily writes an all-defaults index while exiting 0. The workflow then commits that file, wiping any previously computed per-PR tuning without any visible failure. Consider exiting non-zero (or leaving the existing file untouched) when the PR listing request fails.
Was this helpful? React with 👍 or 👎 to provide feedback.
|
sha: a87f7fb @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #156 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
…d commingle-swarm web bundle
| timeout-minutes: 10 | ||
| permissions: | ||
| contents: read | ||
| contents: write |
There was a problem hiding this comment.
🟨 Scheduled workflow gains write access to repository contents and auto-pushes commits to the branch
The sweep job's permissions were widened from contents: read to contents: write (.github/workflows/agent-continuous-ops.yml:37) and a new final step commits generated files and pushes them to ${{ github.ref }} using the checkout-persisted credentials (.github/workflows/agent-continuous-ops.yml:268-280). Any script executed earlier in the job (scripts/ci/calculate_lag_index.py) now runs in a job holding a write-capable token, and its output is committed unreviewed to the branch the workflow ran on (the default branch for schedule runs).
Was this helpful? React with 👍 or 👎 to provide feedback.
…156/#153) Merge PR #178 — dynamic lag index, response_time SSOT, gemini-dispatch review-comment fix. Review threads resolved (Devin/Qodo notes tracked as follow-ups: section splice, schema v2 merge, pagination). GitLab status non-blocking per OPERATOR priority matrix / #95. Signed-off-by: Grok (OPERATOR) / archW1z
This PR upgrades the GitHub Actions continuous operations workflow to operate more continuously and dynamically.
By changing the schedule cron to run every hour and introducing
scripts/ci/calculate_lag_index.py, the workflow dynamically calculates a response time lag index based on historical timeline comment and commit data. It distinguishes between message responses ("I'm working on it" status) and programmatic responses (pushed commits or reviews).The computed metrics are saved in
docs/ops/response_time_lag_index.jsonand rendered into a dynamic table inside a newly established Single Source of Truth documentdocs/ops/LANE_CONSOLIDATION_SSOT.mdwhich lists timing quotas and cooldown configurations for all GHA workflows. The continuous ops workflow loads this JSON file to apply customized dynamic debounces and stale limits for each pull request.Additionally, we fixed an API error bug in
gemini-dispatch.ymlby callingcreateForPullRequestReviewCommentinstead ofcreateForIssueCommentonpull_request_review_commentevents. All unit tests compile and pass successfully.Fixes #155
PR created automatically by Jules for task 5720376583248325329 started by @timerloggedout-spec