fix: apply guarded projectclownfish merges
This commit is contained in:
parent
cace3045a4
commit
fb5d06b2bd
@ -140,7 +140,9 @@ node scripts/import-ghcrawl-clusters.mjs --from-ghcrawl --limit 40 \
|
||||
--repo openclaw/openclaw \
|
||||
--mode autonomous \
|
||||
--suffix autonomous-smoke \
|
||||
--allow-instant-close
|
||||
--allow-instant-close \
|
||||
--allow-merge \
|
||||
--allow-post-merge-close
|
||||
```
|
||||
|
||||
The importer skips existing ghcrawl IDs and security-sensitive clusters by default. Use explicit IDs only when you have inspected them first; do not pass `--include-security`.
|
||||
@ -234,7 +236,7 @@ Say "safe to ramp" only when all are true:
|
||||
- latest canaries run on the current SHA;
|
||||
- no worker result uses `executed`;
|
||||
- no close action targets a closed item;
|
||||
- applicator executed only planned duplicate/superseded/fixed-by-candidate close actions;
|
||||
- applicator executed only planned duplicate/superseded/fixed-by-candidate close actions or guarded clean merge actions;
|
||||
- `CLOWNFISH_ALLOW_EXECUTE` is back to `0`;
|
||||
- active runs are expected and on the intended SHA;
|
||||
- artifacts are downloaded or easy to retrieve by run URL.
|
||||
|
||||
13
README.md
13
README.md
@ -41,7 +41,7 @@ The default workflow is proposal-first. It does not comment or close unless a jo
|
||||
|
||||
## Dashboard
|
||||
|
||||
Last dashboard update: Apr 26, 2026, 01:27 UTC
|
||||
Last dashboard update: Apr 26, 2026, 01:36 UTC
|
||||
|
||||
<!-- projectclownfish-dashboard:start -->
|
||||
State: Blocked actions need triage
|
||||
@ -62,6 +62,7 @@ Scope: 32 latest cluster reports. Run attempts are tracked as audit history only
|
||||
| Open PRs tracked | 86 | 76.8% |
|
||||
| Closed unmerged PRs tracked | 20 | 17.9% |
|
||||
| Completed close actions | 16 | 88.9% |
|
||||
| Completed merge actions | 0 | 0.0% |
|
||||
| Duplicate closes | 16 | 100.0% |
|
||||
| Superseded closes | 0 | 0.0% |
|
||||
| Fixed-by-candidate closes | 0 | 0.0% |
|
||||
@ -114,10 +115,10 @@ Each cluster job:
|
||||
4. Runs Codex with repo-local policy prompts and JSON output schema in a read-only sandbox.
|
||||
5. Writes structured run artifacts under `.projectclownfish/runs/`.
|
||||
6. Reviews the worker artifact with deterministic safety checks.
|
||||
7. Applies only safe close/comment actions through `scripts/apply-result.mjs`.
|
||||
7. Applies guarded close/comment and explicit merge actions through `scripts/apply-result.mjs`.
|
||||
8. Publishes a sanitized result ledger back to this repo under `results/`, `closed/`, `apply-report.json`, and this README dashboard.
|
||||
|
||||
Codex does not receive a GitHub token. The runner preflights GitHub state before model execution, then Codex receives those artifacts and returns JSON only. The applicator re-fetches the target item, checks `updated_at`, blocks maintainer-authored items, writes an idempotent close comment, and closes only supported duplicate/superseded/fixed-by-candidate actions.
|
||||
Codex does not receive a GitHub token. The runner preflights GitHub state before model execution, then Codex receives those artifacts and returns JSON only. The applicator re-fetches the target item, checks `updated_at`, blocks unsafe closeouts, writes idempotent close comments, closes supported duplicate/superseded/fixed-by-candidate actions, and can squash-merge explicitly allowed clean PR actions.
|
||||
|
||||
Runs for the same job path and mode are queued instead of running concurrently. The workflow uses Node 24 and `ubuntu-latest` for ClawSweeper parity; other hosted runners are opt-in.
|
||||
|
||||
@ -126,8 +127,8 @@ Full worker prompts, Codex transcripts, and raw artifacts stay in GitHub Actions
|
||||
## Modes
|
||||
|
||||
- `plan`: produces recommendations only.
|
||||
- `execute`: can apply reviewed safe close actions from structured JSON.
|
||||
- `autonomous`: adds live cluster preflight and fix-artifact generation. It may recommend a canonical fix path, but direct mutation still goes through the applicator.
|
||||
- `execute`: can apply reviewed safe close and explicit clean merge actions from structured JSON.
|
||||
- `autonomous`: adds live cluster preflight and fix-artifact generation. It may recommend and drive a canonical fix path, but direct mutation still goes through the applicator.
|
||||
- `needs_human`: any unclear canonical choice, stale cluster state, failing checks, conflict, broad fix, or independent report should land here.
|
||||
- Automated reviewer feedback must be cleared during autonomous PR work. Greptile, Codex, Asile, CodeRabbit, Copilot, and similar bot comments must be addressed, proven non-actionable, or escalated before any merge or post-merge closeout recommendation.
|
||||
|
||||
@ -153,7 +154,7 @@ npm run import-low-signal -- --limit 20 --batch-size 5 --mode autonomous --sort
|
||||
|
||||
# Stage the next largest active ghcrawl clusters, skipping already-imported and
|
||||
# security-sensitive clusters by default.
|
||||
npm run import-ghcrawl -- --from-ghcrawl --limit 40 --mode autonomous --suffix autonomous-smoke --allow-instant-close
|
||||
npm run import-ghcrawl -- --from-ghcrawl --limit 40 --mode autonomous --suffix autonomous-smoke --allow-instant-close --allow-merge --allow-post-merge-close
|
||||
|
||||
# Find failed cluster jobs that have not been superseded by a later success.
|
||||
npm run self-heal
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"run_id": "24937679258",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24937679258",
|
||||
"cluster_id": "ghcrawl-143799-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.174Z",
|
||||
"published_at": "2026-04-26T01:36:05.594Z",
|
||||
"target": "#65285",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -24,7 +24,7 @@
|
||||
"run_id": "24937679258",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24937679258",
|
||||
"cluster_id": "ghcrawl-143799-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.174Z",
|
||||
"published_at": "2026-04-26T01:36:05.594Z",
|
||||
"target": "#69920",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -44,7 +44,7 @@
|
||||
"run_id": "24939000666",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939000666",
|
||||
"cluster_id": "ghcrawl-143804-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.229Z",
|
||||
"published_at": "2026-04-26T01:36:05.616Z",
|
||||
"target": "#70373",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -64,7 +64,7 @@
|
||||
"run_id": "24939001644",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939001644",
|
||||
"cluster_id": "ghcrawl-143805-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.233Z",
|
||||
"published_at": "2026-04-26T01:36:05.618Z",
|
||||
"target": "#65153",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -84,7 +84,7 @@
|
||||
"run_id": "24939007967",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939007967",
|
||||
"cluster_id": "ghcrawl-143814-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.282Z",
|
||||
"published_at": "2026-04-26T01:36:05.637Z",
|
||||
"target": "#64750",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -104,7 +104,7 @@
|
||||
"run_id": "24939008778",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939008778",
|
||||
"cluster_id": "ghcrawl-143815-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.285Z",
|
||||
"published_at": "2026-04-26T01:36:05.638Z",
|
||||
"target": "#50541",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -124,7 +124,7 @@
|
||||
"run_id": "24939008778",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939008778",
|
||||
"cluster_id": "ghcrawl-143815-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.285Z",
|
||||
"published_at": "2026-04-26T01:36:05.638Z",
|
||||
"target": "#50691",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -144,7 +144,7 @@
|
||||
"run_id": "24939009401",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939009401",
|
||||
"cluster_id": "ghcrawl-143816-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.293Z",
|
||||
"published_at": "2026-04-26T01:36:05.641Z",
|
||||
"target": "#70180",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -164,7 +164,7 @@
|
||||
"run_id": "24939009401",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939009401",
|
||||
"cluster_id": "ghcrawl-143816-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.293Z",
|
||||
"published_at": "2026-04-26T01:36:05.641Z",
|
||||
"target": "#65832",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -184,7 +184,7 @@
|
||||
"run_id": "24939009401",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939009401",
|
||||
"cluster_id": "ghcrawl-143816-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.293Z",
|
||||
"published_at": "2026-04-26T01:36:05.641Z",
|
||||
"target": "#66758",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -204,7 +204,7 @@
|
||||
"run_id": "24939009401",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939009401",
|
||||
"cluster_id": "ghcrawl-143816-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.293Z",
|
||||
"published_at": "2026-04-26T01:36:05.641Z",
|
||||
"target": "#67406",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -224,7 +224,7 @@
|
||||
"run_id": "24939010877",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939010877",
|
||||
"cluster_id": "ghcrawl-143818-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.301Z",
|
||||
"published_at": "2026-04-26T01:36:05.648Z",
|
||||
"target": "#54475",
|
||||
"action": "close_superseded",
|
||||
"status": "blocked",
|
||||
@ -244,7 +244,7 @@
|
||||
"run_id": "24939011554",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939011554",
|
||||
"cluster_id": "ghcrawl-143819-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.304Z",
|
||||
"published_at": "2026-04-26T01:36:05.650Z",
|
||||
"target": "#67029",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -264,7 +264,7 @@
|
||||
"run_id": "24939011554",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939011554",
|
||||
"cluster_id": "ghcrawl-143819-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.304Z",
|
||||
"published_at": "2026-04-26T01:36:05.650Z",
|
||||
"target": "#69886",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -284,7 +284,7 @@
|
||||
"run_id": "24939011554",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939011554",
|
||||
"cluster_id": "ghcrawl-143819-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.304Z",
|
||||
"published_at": "2026-04-26T01:36:05.650Z",
|
||||
"target": "#70353",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -304,7 +304,7 @@
|
||||
"run_id": "24939011554",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939011554",
|
||||
"cluster_id": "ghcrawl-143819-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.304Z",
|
||||
"published_at": "2026-04-26T01:36:05.650Z",
|
||||
"target": "#70395",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -324,7 +324,7 @@
|
||||
"run_id": "24939011554",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24939011554",
|
||||
"cluster_id": "ghcrawl-143819-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.304Z",
|
||||
"published_at": "2026-04-26T01:36:05.650Z",
|
||||
"target": "#71133",
|
||||
"action": "close_duplicate",
|
||||
"status": "executed",
|
||||
@ -344,7 +344,7 @@
|
||||
"run_id": "24943077025",
|
||||
"run_url": "https://github.com/openclaw/projectclownfish/actions/runs/24943077025",
|
||||
"cluster_id": "ghcrawl-143810-autonomous-smoke",
|
||||
"published_at": "2026-04-26T01:27:46.319Z",
|
||||
"published_at": "2026-04-26T01:36:05.666Z",
|
||||
"target": "#41451",
|
||||
"action": "close_duplicate",
|
||||
"status": "blocked",
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939008778"
|
||||
target: "#50541"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.285Z"
|
||||
closed_at: "2026-04-26T01:36:05.638Z"
|
||||
---
|
||||
|
||||
# #50541 closed by ghcrawl-143815-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939008778"
|
||||
target: "#50691"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.285Z"
|
||||
closed_at: "2026-04-26T01:36:05.638Z"
|
||||
---
|
||||
|
||||
# #50691 closed by ghcrawl-143815-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939007967"
|
||||
target: "#64750"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.282Z"
|
||||
closed_at: "2026-04-26T01:36:05.637Z"
|
||||
---
|
||||
|
||||
# #64750 closed by ghcrawl-143814-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939001644"
|
||||
target: "#65153"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.233Z"
|
||||
closed_at: "2026-04-26T01:36:05.618Z"
|
||||
---
|
||||
|
||||
# #65153 closed by ghcrawl-143805-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24937679258"
|
||||
target: "#65285"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.174Z"
|
||||
closed_at: "2026-04-26T01:36:05.594Z"
|
||||
---
|
||||
|
||||
# #65285 closed by ghcrawl-143799-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939009401"
|
||||
target: "#65832"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.293Z"
|
||||
closed_at: "2026-04-26T01:36:05.641Z"
|
||||
---
|
||||
|
||||
# #65832 closed by ghcrawl-143816-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939009401"
|
||||
target: "#66758"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.293Z"
|
||||
closed_at: "2026-04-26T01:36:05.641Z"
|
||||
---
|
||||
|
||||
# #66758 closed by ghcrawl-143816-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939011554"
|
||||
target: "#67029"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.304Z"
|
||||
closed_at: "2026-04-26T01:36:05.650Z"
|
||||
---
|
||||
|
||||
# #67029 closed by ghcrawl-143819-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939009401"
|
||||
target: "#67406"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.293Z"
|
||||
closed_at: "2026-04-26T01:36:05.641Z"
|
||||
---
|
||||
|
||||
# #67406 closed by ghcrawl-143816-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939011554"
|
||||
target: "#69886"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.304Z"
|
||||
closed_at: "2026-04-26T01:36:05.650Z"
|
||||
---
|
||||
|
||||
# #69886 closed by ghcrawl-143819-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24937679258"
|
||||
target: "#69920"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.174Z"
|
||||
closed_at: "2026-04-26T01:36:05.594Z"
|
||||
---
|
||||
|
||||
# #69920 closed by ghcrawl-143799-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939009401"
|
||||
target: "#70180"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.293Z"
|
||||
closed_at: "2026-04-26T01:36:05.641Z"
|
||||
---
|
||||
|
||||
# #70180 closed by ghcrawl-143816-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939011554"
|
||||
target: "#70353"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.304Z"
|
||||
closed_at: "2026-04-26T01:36:05.650Z"
|
||||
---
|
||||
|
||||
# #70353 closed by ghcrawl-143819-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939000666"
|
||||
target: "#70373"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.229Z"
|
||||
closed_at: "2026-04-26T01:36:05.616Z"
|
||||
---
|
||||
|
||||
# #70373 closed by ghcrawl-143804-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939011554"
|
||||
target: "#70395"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.304Z"
|
||||
closed_at: "2026-04-26T01:36:05.650Z"
|
||||
---
|
||||
|
||||
# #70395 closed by ghcrawl-143819-autonomous-smoke
|
||||
|
||||
@ -5,7 +5,7 @@ run_id: "24939011554"
|
||||
target: "#71133"
|
||||
action: "close_duplicate"
|
||||
classification: "duplicate"
|
||||
closed_at: "2026-04-26T01:27:46.304Z"
|
||||
closed_at: "2026-04-26T01:36:05.650Z"
|
||||
---
|
||||
|
||||
# #71133 closed by ghcrawl-143819-autonomous-smoke
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24930312265"
|
||||
head_sha: "b9098f198a6618ccfe5af684127241fe19029079"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.126Z"
|
||||
published_at: "2026-04-26T01:36:05.562Z"
|
||||
canonical: null
|
||||
canonical_issue: null
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24931506639"
|
||||
head_sha: "9545956f6378b1fee5e100ac52da014bcba5047b"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.149Z"
|
||||
published_at: "2026-04-26T01:36:05.576Z"
|
||||
canonical: "#61124"
|
||||
canonical_issue: "#61124"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24943078775"
|
||||
head_sha: "3160a4e666957ca2e0f65fdc0a4d41ba982f99b1"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.329Z"
|
||||
published_at: "2026-04-26T01:36:05.671Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/70678"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/70678"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24936633125"
|
||||
head_sha: "26aea6dfd2d7f0535f43131bbfd4c1d5d934edbb"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.152Z"
|
||||
published_at: "2026-04-26T01:36:05.579Z"
|
||||
canonical: "#70678"
|
||||
canonical_issue: "#70678"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24931325652"
|
||||
head_sha: "75185936126d75ebb182e229f44f6cda4edd81cd"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.142Z"
|
||||
published_at: "2026-04-26T01:36:05.571Z"
|
||||
canonical: "#67335"
|
||||
canonical_issue: "#67335"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24938997703"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.212Z"
|
||||
published_at: "2026-04-26T01:36:05.602Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/pull/50141"
|
||||
canonical_issue: null
|
||||
canonical_pr: "https://github.com/openclaw/openclaw/pull/50141"
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24931170014"
|
||||
head_sha: "e6fc44c785086090541174c0309c5ed6ca780083"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.135Z"
|
||||
published_at: "2026-04-26T01:36:05.566Z"
|
||||
canonical: "#69147"
|
||||
canonical_issue: "#69147"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24936633679"
|
||||
head_sha: "26aea6dfd2d7f0535f43131bbfd4c1d5d934edbb"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.156Z"
|
||||
published_at: "2026-04-26T01:36:05.582Z"
|
||||
canonical: "#51469"
|
||||
canonical_issue: "#51469"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24931326064"
|
||||
head_sha: "75185936126d75ebb182e229f44f6cda4edd81cd"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.146Z"
|
||||
published_at: "2026-04-26T01:36:05.573Z"
|
||||
canonical: null
|
||||
canonical_issue: null
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24937679258"
|
||||
head_sha: "71faa495f89c028a67e9031c6b9e43359a89ecaa"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.174Z"
|
||||
published_at: "2026-04-26T01:36:05.594Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/61741"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/61741"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24936634290"
|
||||
head_sha: "26aea6dfd2d7f0535f43131bbfd4c1d5d934edbb"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.160Z"
|
||||
published_at: "2026-04-26T01:36:05.584Z"
|
||||
canonical: "#61741"
|
||||
canonical_issue: "#61741"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24937905618"
|
||||
head_sha: "30ab2327f6f8b0ff0fe89a5e798b06494ef7e237"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "executed"
|
||||
published_at: "2026-04-26T01:27:46.185Z"
|
||||
published_at: "2026-04-26T01:36:05.598Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/69594"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/69594"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24936634921"
|
||||
head_sha: "26aea6dfd2d7f0535f43131bbfd4c1d5d934edbb"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.162Z"
|
||||
published_at: "2026-04-26T01:36:05.586Z"
|
||||
canonical: "#69594"
|
||||
canonical_issue: "#69594"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24943078008"
|
||||
head_sha: "3160a4e666957ca2e0f65fdc0a4d41ba982f99b1"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.324Z"
|
||||
published_at: "2026-04-26T01:36:05.669Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/pull/50020"
|
||||
canonical_issue: null
|
||||
canonical_pr: "https://github.com/openclaw/openclaw/pull/50020"
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24938999617"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.224Z"
|
||||
published_at: "2026-04-26T01:36:05.613Z"
|
||||
canonical: null
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/57812"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939000666"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.229Z"
|
||||
published_at: "2026-04-26T01:36:05.616Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/68508"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/68508"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939001644"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.233Z"
|
||||
published_at: "2026-04-26T01:36:05.618Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/62560"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/62560"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939002551"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.237Z"
|
||||
published_at: "2026-04-26T01:36:05.619Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/42099"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/42099"
|
||||
canonical_pr: "https://github.com/openclaw/openclaw/pull/42192"
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939003369"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.241Z"
|
||||
published_at: "2026-04-26T01:36:05.622Z"
|
||||
canonical: null
|
||||
canonical_issue: null
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939004182"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.246Z"
|
||||
published_at: "2026-04-26T01:36:05.624Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/66875"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/66875"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939004802"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.266Z"
|
||||
published_at: "2026-04-26T01:36:05.627Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/pull/68641"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/68605"
|
||||
canonical_pr: "https://github.com/openclaw/openclaw/pull/68641"
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24943077025"
|
||||
head_sha: "3160a4e666957ca2e0f65fdc0a4d41ba982f99b1"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.319Z"
|
||||
published_at: "2026-04-26T01:36:05.666Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/45982"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/45982"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24943076135"
|
||||
head_sha: "3160a4e666957ca2e0f65fdc0a4d41ba982f99b1"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.313Z"
|
||||
published_at: "2026-04-26T01:36:05.661Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/pull/64713"
|
||||
canonical_issue: null
|
||||
canonical_pr: "https://github.com/openclaw/openclaw/pull/64713"
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939007176"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.278Z"
|
||||
published_at: "2026-04-26T01:36:05.635Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/41330"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/41330"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939007967"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.282Z"
|
||||
published_at: "2026-04-26T01:36:05.637Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/63816"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/63816"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939008778"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.285Z"
|
||||
published_at: "2026-04-26T01:36:05.638Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/49180"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/49180"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939009401"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.293Z"
|
||||
published_at: "2026-04-26T01:36:05.641Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/33185"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/33185"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939010238"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.298Z"
|
||||
published_at: "2026-04-26T01:36:05.645Z"
|
||||
canonical: null
|
||||
canonical_issue: null
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939010877"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.301Z"
|
||||
published_at: "2026-04-26T01:36:05.648Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/pull/52142"
|
||||
canonical_issue: null
|
||||
canonical_pr: "https://github.com/openclaw/openclaw/pull/52142"
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939011554"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.304Z"
|
||||
published_at: "2026-04-26T01:36:05.650Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/68252"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/68252"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939012263"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "planned"
|
||||
published_at: "2026-04-26T01:27:46.308Z"
|
||||
published_at: "2026-04-26T01:36:05.656Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/43119"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/43119"
|
||||
canonical_pr: null
|
||||
|
||||
@ -7,7 +7,7 @@ run_url: "https://github.com/openclaw/projectclownfish/actions/runs/24939012932"
|
||||
head_sha: "7db1f986bd485f7b71752bc77e40097172d6b6ef"
|
||||
workflow_conclusion: "success"
|
||||
result_status: "needs_human"
|
||||
published_at: "2026-04-26T01:27:46.310Z"
|
||||
published_at: "2026-04-26T01:36:05.659Z"
|
||||
canonical: "https://github.com/openclaw/openclaw/issues/58443"
|
||||
canonical_issue: "https://github.com/openclaw/openclaw/issues/58443"
|
||||
canonical_pr: null
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T01:06:44Z",
|
||||
"result_status": "planned",
|
||||
"source_job": null,
|
||||
"published_at": "2026-04-26T01:27:46.120Z",
|
||||
"published_at": "2026-04-26T01:36:05.554Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T01:08:39Z",
|
||||
"result_status": "planned",
|
||||
"source_job": null,
|
||||
"published_at": "2026-04-26T01:27:46.124Z",
|
||||
"published_at": "2026-04-26T01:36:05.561Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T11:54:56Z",
|
||||
"result_status": "planned",
|
||||
"source_job": null,
|
||||
"published_at": "2026-04-26T01:27:46.126Z",
|
||||
"published_at": "2026-04-26T01:36:05.562Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T11:59:32Z",
|
||||
"result_status": "planned",
|
||||
"source_job": null,
|
||||
"published_at": "2026-04-26T01:27:46.128Z",
|
||||
"published_at": "2026-04-26T01:36:05.563Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T12:15:59Z",
|
||||
"result_status": "planned",
|
||||
"source_job": null,
|
||||
"published_at": "2026-04-26T01:27:46.130Z",
|
||||
"published_at": "2026-04-26T01:36:05.563Z",
|
||||
"canonical": "#69147",
|
||||
"canonical_issue": "#69147",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T12:21:25Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": null,
|
||||
"published_at": "2026-04-26T01:27:46.132Z",
|
||||
"published_at": "2026-04-26T01:36:05.564Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T12:49:53Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143796-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.135Z",
|
||||
"published_at": "2026-04-26T01:36:05.566Z",
|
||||
"canonical": "#69147",
|
||||
"canonical_issue": "#69147",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T12:56:40Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143790-discord-health-monitor-restart-crashes-gateway-with-max-reconnec.md",
|
||||
"published_at": "2026-04-26T01:27:46.138Z",
|
||||
"published_at": "2026-04-26T01:36:05.568Z",
|
||||
"canonical": "#61124",
|
||||
"canonical_issue": "#61124",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T12:59:27Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143794-bug-macos-openclaw-gateway-restart-fails-when-invoked-from-agent.md",
|
||||
"published_at": "2026-04-26T01:27:46.142Z",
|
||||
"published_at": "2026-04-26T01:36:05.571Z",
|
||||
"canonical": "#67335",
|
||||
"canonical_issue": "#67335",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T12:57:03Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143798-bug-managed-browser-and-user-browser-attach-both-fail-on-macos-d.md",
|
||||
"published_at": "2026-04-26T01:27:46.146Z",
|
||||
"published_at": "2026-04-26T01:36:05.573Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T13:06:12Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143790-discord-health-monitor-restart-crashes-gateway-with-max-reconnec.md",
|
||||
"published_at": "2026-04-26T01:27:46.149Z",
|
||||
"published_at": "2026-04-26T01:36:05.576Z",
|
||||
"canonical": "#61124",
|
||||
"canonical_issue": "#61124",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T17:40:57Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143793-bug-whatsapp-499-reconnection-loop-inactivity-timer-not-reset-af.md",
|
||||
"published_at": "2026-04-26T01:27:46.152Z",
|
||||
"published_at": "2026-04-26T01:36:05.579Z",
|
||||
"canonical": "#70678",
|
||||
"canonical_issue": "#70678",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T17:41:14Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143797-bug-local-gateway-cli-handshake-fails-probe-timeout-gateway-call.md",
|
||||
"published_at": "2026-04-26T01:27:46.156Z",
|
||||
"published_at": "2026-04-26T01:36:05.582Z",
|
||||
"canonical": "#51469",
|
||||
"canonical_issue": "#51469",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T17:40:09Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143799-unhandled-promise-rejection-agent-listener-invoked-outside-activ.md",
|
||||
"published_at": "2026-04-26T01:27:46.160Z",
|
||||
"published_at": "2026-04-26T01:36:05.584Z",
|
||||
"canonical": "#61741",
|
||||
"canonical_issue": "#61741",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T17:40:30Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143800-bug-cron-announce-delivery-reports-success-but-messages-never-ar.md",
|
||||
"published_at": "2026-04-26T01:27:46.162Z",
|
||||
"published_at": "2026-04-26T01:36:05.586Z",
|
||||
"canonical": "#69594",
|
||||
"canonical_issue": "#69594",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T17:58:08Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143799-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.165Z",
|
||||
"published_at": "2026-04-26T01:36:05.588Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T18:14:15Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143799-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.168Z",
|
||||
"published_at": "2026-04-26T01:36:05.589Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T18:27:07Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143799-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.170Z",
|
||||
"published_at": "2026-04-26T01:36:05.591Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T18:35:05Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143799-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.174Z",
|
||||
"published_at": "2026-04-26T01:36:05.594Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/61741",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T18:58:23Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143793-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.180Z",
|
||||
"published_at": "2026-04-26T01:36:05.596Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/70678",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/70678",
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/71466",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T18:47:29Z",
|
||||
"result_status": "executed",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143800-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.185Z",
|
||||
"published_at": "2026-04-26T01:36:05.598Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/69594",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/69594",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:45:30Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143795-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.212Z",
|
||||
"published_at": "2026-04-26T01:36:05.602Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/50141",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/50141",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:45:35Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143801-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.219Z",
|
||||
"published_at": "2026-04-26T01:36:05.605Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/50020",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/50020",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:43:45Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143803-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.224Z",
|
||||
"published_at": "2026-04-26T01:36:05.613Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/57812",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:45:05Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143804-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.229Z",
|
||||
"published_at": "2026-04-26T01:36:05.616Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/68508",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/68508",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:44:53Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143805-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.233Z",
|
||||
"published_at": "2026-04-26T01:36:05.618Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/62560",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/62560",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:49:25Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143806-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.237Z",
|
||||
"published_at": "2026-04-26T01:36:05.619Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/42099",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/42099",
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/42192",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:46:06Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143807-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.241Z",
|
||||
"published_at": "2026-04-26T01:36:05.622Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:44:15Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143808-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.246Z",
|
||||
"published_at": "2026-04-26T01:36:05.624Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/66875",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/66875",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:50:18Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143809-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.266Z",
|
||||
"published_at": "2026-04-26T01:36:05.627Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/68641",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/68605",
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/68641",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:48:57Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143810-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.271Z",
|
||||
"published_at": "2026-04-26T01:36:05.632Z",
|
||||
"canonical": "#45985",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/45985",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:43:30Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143811-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.275Z",
|
||||
"published_at": "2026-04-26T01:36:05.633Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/64713",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/64713",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:45:29Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143813-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.278Z",
|
||||
"published_at": "2026-04-26T01:36:05.635Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/41330",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/41330",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:44:32Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143814-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.282Z",
|
||||
"published_at": "2026-04-26T01:36:05.637Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/63816",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/63816",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:46:23Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143815-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.285Z",
|
||||
"published_at": "2026-04-26T01:36:05.638Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/49180",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/49180",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:58:04Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143816-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.293Z",
|
||||
"published_at": "2026-04-26T01:36:05.641Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/33185",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/33185",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:47:54Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143817-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.298Z",
|
||||
"published_at": "2026-04-26T01:36:05.645Z",
|
||||
"canonical": null,
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:49:00Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143818-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.301Z",
|
||||
"published_at": "2026-04-26T01:36:05.648Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/52142",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/52142",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:53:15Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143819-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.304Z",
|
||||
"published_at": "2026-04-26T01:36:05.650Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/68252",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/68252",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:47:49Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143820-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.308Z",
|
||||
"published_at": "2026-04-26T01:36:05.656Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/43119",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/43119",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T19:47:34Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143821-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.310Z",
|
||||
"published_at": "2026-04-26T01:36:05.659Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/58443",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/58443",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T23:27:26Z",
|
||||
"result_status": "planned",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143811-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.313Z",
|
||||
"published_at": "2026-04-26T01:36:05.661Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/64713",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/64713",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T23:46:17Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143810-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.319Z",
|
||||
"published_at": "2026-04-26T01:36:05.666Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/45982",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/45982",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T23:44:43Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143801-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.324Z",
|
||||
"published_at": "2026-04-26T01:36:05.669Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/pull/50020",
|
||||
"canonical_issue": null,
|
||||
"canonical_pr": "https://github.com/openclaw/openclaw/pull/50020",
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"workflow_updated_at": "2026-04-25T23:27:35Z",
|
||||
"result_status": "needs_human",
|
||||
"source_job": "jobs/openclaw/ghcrawl-143793-autonomous-smoke.md",
|
||||
"published_at": "2026-04-26T01:27:46.329Z",
|
||||
"published_at": "2026-04-26T01:36:05.671Z",
|
||||
"canonical": "https://github.com/openclaw/openclaw/issues/70678",
|
||||
"canonical_issue": "https://github.com/openclaw/openclaw/issues/70678",
|
||||
"canonical_pr": null,
|
||||
|
||||
@ -12,8 +12,12 @@ const CLOSE_ACTIONS = new Set([
|
||||
"close_superseded",
|
||||
"close_fixed_by_candidate",
|
||||
"close_low_signal",
|
||||
"post_merge_close",
|
||||
]);
|
||||
const MERGE_ACTIONS = new Set(["merge_candidate", "merge_canonical"]);
|
||||
const CLOSE_CLASSIFICATIONS = new Set(["duplicate", "superseded", "fixed_by_candidate", "low_signal"]);
|
||||
const PASSING_CHECK_CONCLUSIONS = new Set(["SUCCESS", "SKIPPED", "NEUTRAL"]);
|
||||
const CLEAN_MERGE_STATES = new Set(["CLEAN"]);
|
||||
|
||||
const args = parseArgs(process.argv.slice(2));
|
||||
const jobPath = args._[0];
|
||||
@ -47,13 +51,6 @@ if (!["execute", "autonomous"].includes(job.frontmatter.mode)) {
|
||||
if (process.env.CLOWNFISH_ALLOW_EXECUTE !== "1") {
|
||||
throw new Error("refusing apply: CLOWNFISH_ALLOW_EXECUTE must be 1");
|
||||
}
|
||||
if (!job.frontmatter.allowed_actions.includes("close")) {
|
||||
throw new Error("refusing apply: job does not allow close");
|
||||
}
|
||||
if (!job.frontmatter.allowed_actions.includes("comment")) {
|
||||
throw new Error("refusing apply: job does not allow comment");
|
||||
}
|
||||
|
||||
const resultPath = resultPathArg ? path.resolve(resultPathArg) : findLatestResultPath();
|
||||
const result = JSON.parse(fs.readFileSync(resultPath, "utf8"));
|
||||
if (result.repo !== job.frontmatter.repo) {
|
||||
@ -144,9 +141,32 @@ function applyAction({ job, result, action, dryRun, allowMissingUpdatedAt }) {
|
||||
if (action.status !== "planned") {
|
||||
return { ...base, status: "skipped", reason: `action status is ${action.status}` };
|
||||
}
|
||||
if (!CLOSE_ACTIONS.has(actionName)) {
|
||||
return { ...base, status: "skipped", reason: "action is not an auto-closure action" };
|
||||
if (MERGE_ACTIONS.has(actionName)) {
|
||||
return applyMergeAction({ job, result, action, dryRun, allowMissingUpdatedAt, target, base });
|
||||
}
|
||||
if (!CLOSE_ACTIONS.has(actionName)) {
|
||||
return { ...base, status: "skipped", reason: "action is not an applicator action" };
|
||||
}
|
||||
|
||||
return applyCloseAction({ job, result, action, dryRun, allowMissingUpdatedAt, target, base, actionName, classification, canonical, candidateFix, idempotencyKey });
|
||||
}
|
||||
|
||||
function applyCloseAction({
|
||||
job,
|
||||
result,
|
||||
action,
|
||||
dryRun,
|
||||
allowMissingUpdatedAt,
|
||||
target,
|
||||
base,
|
||||
actionName,
|
||||
classification,
|
||||
canonical,
|
||||
candidateFix,
|
||||
idempotencyKey,
|
||||
}) {
|
||||
const closePolicyBlock = validateClosePolicy({ job, actionName });
|
||||
if (closePolicyBlock) return { ...base, status: "blocked", reason: closePolicyBlock };
|
||||
if (!CLOSE_CLASSIFICATIONS.has(classification)) {
|
||||
return {
|
||||
...base,
|
||||
@ -154,6 +174,9 @@ function applyAction({ job, result, action, dryRun, allowMissingUpdatedAt }) {
|
||||
reason: "auto-closure requires duplicate, superseded, fixed_by_candidate, or low_signal classification",
|
||||
};
|
||||
}
|
||||
if (actionName === "post_merge_close" && job.frontmatter.allow_post_merge_close !== true) {
|
||||
return { ...base, status: "blocked", reason: "post-merge close requires allow_post_merge_close: true" };
|
||||
}
|
||||
if (!job.frontmatter.candidates.map(normalizeIssueRef).includes(target)) {
|
||||
return { ...base, status: "blocked", reason: "target is not listed in job candidates" };
|
||||
}
|
||||
@ -173,6 +196,10 @@ function applyAction({ job, result, action, dryRun, allowMissingUpdatedAt }) {
|
||||
if (candidateFix && !allowedRefs.has(candidateFix)) {
|
||||
return { ...base, status: "blocked", reason: "candidate fix is not listed in job refs" };
|
||||
}
|
||||
if (actionName === "post_merge_close") {
|
||||
const candidateBlock = validateMergedCandidateFix(result.repo, candidateFix);
|
||||
if (candidateBlock) return { ...base, status: "blocked", reason: candidateBlock };
|
||||
}
|
||||
if (canonical === target || candidateFix === target) {
|
||||
return { ...base, status: "blocked", reason: "target cannot close against itself" };
|
||||
}
|
||||
@ -269,8 +296,166 @@ function applyAction({ job, result, action, dryRun, allowMissingUpdatedAt }) {
|
||||
};
|
||||
}
|
||||
|
||||
function applyMergeAction({ job, result, action, dryRun, allowMissingUpdatedAt, target, base }) {
|
||||
const policyBlock = validateMergePolicy({ job, action });
|
||||
if (policyBlock) return { ...base, status: "blocked", reason: policyBlock };
|
||||
if (!allowedRefs.has(target)) {
|
||||
return { ...base, status: "blocked", reason: "merge target is not listed in job refs" };
|
||||
}
|
||||
if (action.target_kind !== "pull_request") {
|
||||
return { ...base, status: "blocked", reason: "merge action requires pull_request target_kind" };
|
||||
}
|
||||
|
||||
const live = fetchIssue(result.repo, target);
|
||||
if (!live.pull_request) {
|
||||
return { ...base, status: "blocked", reason: "merge target is not a pull request", live_state: live.state };
|
||||
}
|
||||
if (hasSecuritySignal(live)) {
|
||||
return {
|
||||
...base,
|
||||
status: "blocked",
|
||||
reason: "security-sensitive target requires central security triage",
|
||||
live_state: live.state,
|
||||
};
|
||||
}
|
||||
|
||||
const expectedUpdatedAt = action.target_updated_at ?? action.live_updated_at;
|
||||
if (!expectedUpdatedAt && !allowMissingUpdatedAt) {
|
||||
return {
|
||||
...base,
|
||||
status: "blocked",
|
||||
reason: "missing target_updated_at; rerun the worker against live GitHub state",
|
||||
live_state: live.state,
|
||||
live_updated_at: live.updated_at,
|
||||
};
|
||||
}
|
||||
if (expectedUpdatedAt && expectedUpdatedAt !== live.updated_at) {
|
||||
return {
|
||||
...base,
|
||||
status: "blocked",
|
||||
reason: "target changed since worker review",
|
||||
expected_updated_at: expectedUpdatedAt,
|
||||
live_updated_at: live.updated_at,
|
||||
live_state: live.state,
|
||||
};
|
||||
}
|
||||
|
||||
const pullRequest = fetchPullRequest(result.repo, target);
|
||||
const view = fetchPullRequestView(result.repo, target);
|
||||
const mergedAt = pullRequest.merged_at ?? view.mergedAt ?? null;
|
||||
if (mergedAt) {
|
||||
return {
|
||||
...base,
|
||||
status: "executed",
|
||||
reason: "already merged",
|
||||
live_state: "merged",
|
||||
live_updated_at: live.updated_at,
|
||||
merged_at: mergedAt,
|
||||
merge_commit_sha: pullRequest.merge_commit_sha ?? view.mergeCommit?.oid ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
const mergeBlock = validateMergeablePullRequest({ pullRequest, view });
|
||||
if (mergeBlock) {
|
||||
return {
|
||||
...base,
|
||||
status: "blocked",
|
||||
reason: mergeBlock,
|
||||
live_state: live.state,
|
||||
live_updated_at: live.updated_at,
|
||||
};
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
return {
|
||||
...base,
|
||||
status: "planned",
|
||||
reason: "dry run",
|
||||
live_state: live.state,
|
||||
live_updated_at: live.updated_at,
|
||||
merge_method: "squash",
|
||||
};
|
||||
}
|
||||
|
||||
ghWithRetry(["pr", "merge", String(target), "--repo", result.repo, "--squash"]);
|
||||
const merged = fetchPullRequest(result.repo, target);
|
||||
return {
|
||||
...base,
|
||||
status: "executed",
|
||||
reason: "merged by projectclownfish",
|
||||
live_state: "merged",
|
||||
live_updated_at: live.updated_at,
|
||||
merged_at: merged.merged_at ?? null,
|
||||
merge_commit_sha: merged.merge_commit_sha ?? null,
|
||||
merge_method: "squash",
|
||||
};
|
||||
}
|
||||
|
||||
function validateClosePolicy({ job, actionName }) {
|
||||
if (!job.frontmatter.allowed_actions.includes("close")) return "job does not allow close";
|
||||
if (!job.frontmatter.allowed_actions.includes("comment")) return "job does not allow close comments";
|
||||
if ((job.frontmatter.blocked_actions ?? []).includes("close")) return "close is blocked by job frontmatter";
|
||||
if ((job.frontmatter.blocked_actions ?? []).includes("comment")) return "comment is blocked by job frontmatter";
|
||||
if (!["close_low_signal", "post_merge_close"].includes(actionName) && job.frontmatter.allow_instant_close !== true) {
|
||||
return "instant close requires allow_instant_close: true";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function validateMergePolicy({ job, action }) {
|
||||
if (!job.frontmatter.allowed_actions.includes("merge")) return "job does not allow merge";
|
||||
if ((job.frontmatter.blocked_actions ?? []).includes("merge")) return "merge is blocked by job frontmatter";
|
||||
if (job.frontmatter.allow_merge !== true) return "merge requires allow_merge: true";
|
||||
if (!["merge_candidate", "merge_canonical"].includes(String(action.action ?? ""))) {
|
||||
return "unsupported merge action";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function validateMergedCandidateFix(repo, candidateFix) {
|
||||
if (!candidateFix) return "post-merge close requires candidate_fix";
|
||||
const candidate = fetchPullRequest(repo, candidateFix);
|
||||
if (!candidate.merged_at) return "candidate fix is not merged";
|
||||
return "";
|
||||
}
|
||||
|
||||
function validateMergeablePullRequest({ pullRequest, view }) {
|
||||
if (pullRequest.state !== "open") return `pull request is ${pullRequest.state}`;
|
||||
if (pullRequest.draft || view.isDraft) return "pull request is draft";
|
||||
if (String(view.baseRefName ?? pullRequest.base?.ref ?? "") !== "main") return "pull request base is not main";
|
||||
if (view.mergeable !== "MERGEABLE") return `mergeable state is ${view.mergeable || "unknown"}`;
|
||||
if (!CLEAN_MERGE_STATES.has(String(view.mergeStateStatus ?? ""))) {
|
||||
return `merge state status is ${view.mergeStateStatus || "unknown"}`;
|
||||
}
|
||||
if (["CHANGES_REQUESTED", "REVIEW_REQUIRED"].includes(String(view.reviewDecision ?? ""))) {
|
||||
return `review decision is ${view.reviewDecision}`;
|
||||
}
|
||||
const checkBlock = validateStatusChecks(view.statusCheckRollup ?? []);
|
||||
if (checkBlock) return checkBlock;
|
||||
return "";
|
||||
}
|
||||
|
||||
function validateStatusChecks(checks) {
|
||||
if (!Array.isArray(checks) || checks.length === 0) return "no PR checks found";
|
||||
const blockers = [];
|
||||
for (const check of checks) {
|
||||
const name = check.name ?? check.context ?? "unknown check";
|
||||
const status = String(check.status ?? check.state ?? "").toUpperCase();
|
||||
const conclusion = String(check.conclusion ?? "").toUpperCase();
|
||||
if (status && !["COMPLETED", "SUCCESS"].includes(status)) {
|
||||
blockers.push(`${name}: ${status}`);
|
||||
continue;
|
||||
}
|
||||
if (conclusion && !PASSING_CHECK_CONCLUSIONS.has(conclusion)) {
|
||||
blockers.push(`${name}: ${conclusion}`);
|
||||
}
|
||||
}
|
||||
if (blockers.length > 0) return `checks are not clean: ${blockers.slice(0, 5).join(", ")}`;
|
||||
return "";
|
||||
}
|
||||
|
||||
function isApplicatorAction(action) {
|
||||
return CLOSE_ACTIONS.has(String(action?.action ?? ""));
|
||||
return CLOSE_ACTIONS.has(String(action?.action ?? "")) || MERGE_ACTIONS.has(String(action?.action ?? ""));
|
||||
}
|
||||
|
||||
function normalizeIssueRef(value, expectedRepo = "") {
|
||||
@ -294,6 +479,7 @@ function normalizeClassification(action) {
|
||||
if (action.action === "close_low_signal") return "low_signal";
|
||||
if (action.action === "close_superseded") return "superseded";
|
||||
if (action.action === "close_duplicate") return "duplicate";
|
||||
if (action.action === "post_merge_close") return "fixed_by_candidate";
|
||||
return raw;
|
||||
}
|
||||
|
||||
@ -415,6 +601,31 @@ function fetchPullRequest(repo, number) {
|
||||
return ghJson(["api", `repos/${repo}/pulls/${number}`]);
|
||||
}
|
||||
|
||||
function fetchPullRequestView(repo, number) {
|
||||
return ghJson([
|
||||
"pr",
|
||||
"view",
|
||||
String(number),
|
||||
"--repo",
|
||||
repo,
|
||||
"--json",
|
||||
[
|
||||
"baseRefName",
|
||||
"isDraft",
|
||||
"mergeable",
|
||||
"mergeCommit",
|
||||
"mergeStateStatus",
|
||||
"mergedAt",
|
||||
"reviewDecision",
|
||||
"state",
|
||||
"statusCheckRollup",
|
||||
"title",
|
||||
"updatedAt",
|
||||
"url",
|
||||
].join(","),
|
||||
]);
|
||||
}
|
||||
|
||||
function findExistingComment(repo, number, marker, body) {
|
||||
const comments = ghPaged(`repos/${repo}/issues/${number}/comments`);
|
||||
return comments.find((comment) => comment.body?.includes(marker) || comment.body === body);
|
||||
|
||||
@ -12,6 +12,8 @@ const outDir = path.resolve(String(args.out ?? path.join(repoRoot(), "jobs", rep
|
||||
const mode = String(args.mode ?? "plan");
|
||||
const suffix = typeof args.suffix === "string" ? args.suffix : "";
|
||||
const allowInstantClose = Boolean(args["allow-instant-close"]);
|
||||
const allowMerge = Boolean(args["allow-merge"]);
|
||||
const allowPostMergeClose = Boolean(args["allow-post-merge-close"] || allowMerge);
|
||||
const skipExisting = args["skip-existing"] !== "false";
|
||||
const skipSecurity = args["include-security"] !== true && args["skip-security"] !== "false";
|
||||
const fromGhcrawl = Boolean(args["from-ghcrawl"] || args.all);
|
||||
@ -24,7 +26,7 @@ if (clusterIds.length === 0 && fromGhcrawl) {
|
||||
}
|
||||
|
||||
if (clusterIds.length === 0) {
|
||||
console.error("usage: node scripts/import-ghcrawl-clusters.mjs <cluster-id> [...] [--from-ghcrawl] [--limit N] [--repo owner/repo] [--db path] [--out dir] [--mode plan|autonomous] [--suffix name] [--allow-instant-close]");
|
||||
console.error("usage: node scripts/import-ghcrawl-clusters.mjs <cluster-id> [...] [--from-ghcrawl] [--limit N] [--repo owner/repo] [--db path] [--out dir] [--mode plan|autonomous] [--suffix name] [--allow-instant-close] [--allow-merge] [--allow-post-merge-close]");
|
||||
process.exit(2);
|
||||
}
|
||||
if (!["plan", "execute", "autonomous"].includes(mode)) {
|
||||
@ -108,10 +110,11 @@ for (const clusterId of clusterIds) {
|
||||
" - comment",
|
||||
" - label",
|
||||
" - close",
|
||||
...(allowMerge ? [" - merge"] : []),
|
||||
"blocked_actions:",
|
||||
" - force_push",
|
||||
" - bypass_checks",
|
||||
" - merge",
|
||||
...(allowMerge ? [] : [" - merge"]),
|
||||
" - fix",
|
||||
"require_human_for:",
|
||||
" - security_sensitive",
|
||||
@ -131,8 +134,8 @@ for (const clusterId of clusterIds) {
|
||||
? [
|
||||
`allow_instant_close: ${allowInstantClose ? "true" : "false"}`,
|
||||
"allow_fix_pr: false",
|
||||
"allow_merge: false",
|
||||
"allow_post_merge_close: false",
|
||||
`allow_merge: ${allowMerge ? "true" : "false"}`,
|
||||
`allow_post_merge_close: ${allowPostMergeClose ? "true" : "false"}`,
|
||||
]
|
||||
: []),
|
||||
`canonical_hint: ${quoteYaml(canonicalHint(representative))}`,
|
||||
|
||||
@ -12,6 +12,7 @@ const CLOSE_APPLICATOR_ACTIONS = new Set([
|
||||
"close_superseded",
|
||||
"close_fixed_by_candidate",
|
||||
"close_low_signal",
|
||||
"post_merge_close",
|
||||
]);
|
||||
const MERGE_APPLICATOR_ACTIONS = new Set(["merge_candidate", "merge_canonical"]);
|
||||
const APPLICATOR_ACTIONS = new Set([...CLOSE_APPLICATOR_ACTIONS, ...MERGE_APPLICATOR_ACTIONS]);
|
||||
@ -224,6 +225,7 @@ function updateDashboard() {
|
||||
);
|
||||
const executedRows = applyRows.filter((row) => row.action.status === "executed");
|
||||
const closedRows = executedRows.filter((row) => CLOSE_APPLICATOR_ACTIONS.has(String(row.action.action ?? "")));
|
||||
const mergedRows = executedRows.filter((row) => MERGE_APPLICATOR_ACTIONS.has(String(row.action.action ?? "")));
|
||||
const closureRows = hydrateClosureRows(closedRows).sort(sortNewestClosureRowFirst);
|
||||
const projectClownfishMergedRows = trackedPrRows.filter((row) => row.projectClownfishMerged);
|
||||
const blockedRows = applyRows.filter((row) => row.action.status === "blocked");
|
||||
@ -262,6 +264,7 @@ function updateDashboard() {
|
||||
cancelled: latestByCluster.filter((record) => record.workflow_conclusion === "cancelled").length,
|
||||
cleanClusters: cleanClusters.length,
|
||||
closed: closedRows.length,
|
||||
merged: mergedRows.length,
|
||||
trackedPrs: trackedPrRows.length,
|
||||
trackedMergedPrs: projectClownfishMergedRows.length,
|
||||
openTrackedPrs: countRows(trackedPrRows, (row) => row.state === "open"),
|
||||
@ -309,6 +312,7 @@ ${renderMetricRow(
|
||||
percent(totals.closedUnmergedTrackedPrs, totals.trackedPrs),
|
||||
)}
|
||||
${renderMetricRow("Completed close actions", totals.closed, percent(totals.closed, totals.mutationAttempts))}
|
||||
${renderMetricRow("Completed merge actions", totals.merged, percent(totals.merged, totals.mutationAttempts))}
|
||||
${renderMetricRow("Duplicate closes", totals.duplicateCloses, percent(totals.duplicateCloses, totals.closed))}
|
||||
${renderMetricRow("Superseded closes", totals.supersededCloses, percent(totals.supersededCloses, totals.closed))}
|
||||
${renderMetricRow(
|
||||
|
||||
@ -9,8 +9,9 @@ const CLOSE_ACTIONS = new Set([
|
||||
"close_superseded",
|
||||
"close_fixed_by_candidate",
|
||||
"close_low_signal",
|
||||
"close_low_signal",
|
||||
"post_merge_close",
|
||||
]);
|
||||
const MERGE_ACTIONS = new Set(["merge_candidate", "merge_canonical"]);
|
||||
const MUTATING_ACTIONS = new Set([
|
||||
"close",
|
||||
"close_duplicate",
|
||||
@ -145,6 +146,13 @@ function reviewResult(resultPath) {
|
||||
if (candidateRef === normalizeRef(target)) failures.push(`${target} close action candidate points at itself`);
|
||||
}
|
||||
}
|
||||
if (MERGE_ACTIONS.has(name)) {
|
||||
if (!item) failures.push(`${target} merge action missing preflight item`);
|
||||
if (item && item.state !== "open") failures.push(`${target} merge action targets ${item.state} item`);
|
||||
if (item && item.kind !== "pull_request") failures.push(`${target} merge action target is ${item.kind}`);
|
||||
if (action.target_kind !== "pull_request") failures.push(`${target} merge action requires pull_request target_kind`);
|
||||
if (action.status !== "planned") failures.push(`${target} merge action status must be planned`);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.canonical) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user