Summary
gh-aw v0.85.4 configures action-failure issues to expire (168 hours by default) and writes an expiration marker into each generated failure issue, but action-failure expiry is not considered when deciding whether to generate agentics-maintenance.yml.
If no workflow declares another recognized expiry source, compilation omits or deletes the maintenance workflow. The displayed action-failure deadline then has no scheduled close-expired-issues consumer. The failure handler stops reusing an expired individual report, but it does not close that issue, so expired reports can remain open while later failures create additional reports. Grouped parent failure issues also receive an expiration marker, but parent lookup does not enforce it.
I reproduced this with the public v0.85.4 CLI and confirmed the same compiler/runtime paths remain on main at 5107b7bd547ce124f69084dc623e45a539cd17f5.
Minimal reproduction
Compile this standalone workflow with v0.85.4:
---
on:
slash_command:
name: reproduce
events: [issue_comment]
permissions:
contents: read
issues: read
safe-outputs:
add-comment:
max: 1
---
# Minimal reproduction
Reply with a short acknowledgement.
$ gh aw version
gh aw version v0.85.4
$ gh aw compile repro --strict --validate
✓ Compiled 1 workflow: 1 succeeded, 0 warnings
Observed results:
-
repro.lock.yml contains:
GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "168"
-
.github/workflows/agentics-maintenance.yml is absent.
Source trace
- The conclusion-job compiler always injects the configured/default action-failure expiry:
notify_comment_conclusion_helpers.go.
- The public reference says
maintenance.action_failure_issue_expires controls failure-issue expiration and defaults to 168 hours:
ephemerals.md.
handle_agent_failure.cjs reads that value, writes expiration markers to parent/per-run failure issues, and treats an expired individual report as non-reusable:
handle_agent_failure.cjs,
isReusableFailureIssue,
and failure issue creation.
scanWorkflowsForExpires only accounts for explicit discussion/issue/pull-request safe-output expiry and explicit no-op issue reporting:
maintenance_workflow.go.
- When that scan returns false, the compiler omits or deletes
agentics-maintenance.yml:
maintenance_workflow.go.
- The scheduled
close-expired-issues job is generated only as part of maintenance workflow output:
maintenance_workflow_yaml_jobs.go.
Expected behavior
Expiration metadata and available cleanup should remain consistent without silently forcing a scheduled maintenance workflow into every repository. When no cleanup consumer will exist, failure issues should not claim they expire.
Actual behavior
A repository can receive failure issues with checked expiration metadata but no generated scheduled workflow that closes them.
Relationship to #36857
#36857 reported the same producer/consumer mismatch for no-op tracker issues. #37965 aligned maintenance generation with that no-op path. Action-failure issue expiration is a separate producer and is still absent from scanWorkflowsForExpires.
Design constraint
safe-outputs.report-failure-as-issue defaults to true, so treating the implicit 168-hour default as an unconditional maintenance trigger would generate agentics-maintenance.yml for essentially every repository with a gh-aw workflow:
The fix should preserve that opt-in posture rather than merely making action-failure expiry another always-on trigger.
Suggested implementation plan
- Do not use the implicit 168-hour action-failure default as an unconditional reason to generate scheduled maintenance.
- When no recognized expiry source generates maintenance and
maintenance.action_failure_issue_expires was not explicitly configured, suppress the failure-issue expiration marker. The runtime parser may need an explicit disabled value rather than falling back to 168 hours.
- Treat an explicitly configured
maintenance.action_failure_issue_expires value as an opt-in to enforceable expiration: generate maintenance and include that value when selecting the minimum cleanup interval.
- If another recognized expiry source already generates maintenance, preserve action-failure markers because the generic issue sweeper can enforce them.
- Add regression coverage for:
- the implicit default with no maintenance source (no unenforceable marker and no forced schedule);
- an explicit action-failure expiry (maintenance generated);
- coexistence with shorter and longer safe-output expiry values;
- explicit maintenance opt-out behavior.
- Verify expired per-run and grouped parent failure issues are both closed when cleanup is enabled.
- Cover
failure-issue-repo and side-repository maintenance so cleanup runs against the repository where failure issues are created; side-repository workflows do not repair missing cleanup in the primary repository.
- Keep the runtime expiration marker and compile-time maintenance-generation contract synchronized.
Impact
This is an issue-lifecycle/cleanup defect, not a credential or code-execution vulnerability. It can leave stale failure-report issues open and allow additional reports to accumulate after their displayed expiry.
Summary
gh-aw v0.85.4 configures action-failure issues to expire (168 hours by default) and writes an expiration marker into each generated failure issue, but action-failure expiry is not considered when deciding whether to generate
agentics-maintenance.yml.If no workflow declares another recognized expiry source, compilation omits or deletes the maintenance workflow. The displayed action-failure deadline then has no scheduled
close-expired-issuesconsumer. The failure handler stops reusing an expired individual report, but it does not close that issue, so expired reports can remain open while later failures create additional reports. Grouped parent failure issues also receive an expiration marker, but parent lookup does not enforce it.I reproduced this with the public v0.85.4 CLI and confirmed the same compiler/runtime paths remain on
mainat5107b7bd547ce124f69084dc623e45a539cd17f5.Minimal reproduction
Compile this standalone workflow with v0.85.4:
Observed results:
repro.lock.ymlcontains:.github/workflows/agentics-maintenance.ymlis absent.Source trace
notify_comment_conclusion_helpers.go.maintenance.action_failure_issue_expirescontrols failure-issue expiration and defaults to 168 hours:ephemerals.md.handle_agent_failure.cjsreads that value, writes expiration markers to parent/per-run failure issues, and treats an expired individual report as non-reusable:handle_agent_failure.cjs,isReusableFailureIssue,and failure issue creation.
scanWorkflowsForExpiresonly accounts for explicit discussion/issue/pull-request safe-output expiry and explicit no-op issue reporting:maintenance_workflow.go.agentics-maintenance.yml:maintenance_workflow.go.close-expired-issuesjob is generated only as part of maintenance workflow output:maintenance_workflow_yaml_jobs.go.Expected behavior
Expiration metadata and available cleanup should remain consistent without silently forcing a scheduled maintenance workflow into every repository. When no cleanup consumer will exist, failure issues should not claim they expire.
Actual behavior
A repository can receive failure issues with checked expiration metadata but no generated scheduled workflow that closes them.
Relationship to #36857
#36857 reported the same producer/consumer mismatch for no-op tracker issues. #37965 aligned maintenance generation with that no-op path. Action-failure issue expiration is a separate producer and is still absent from
scanWorkflowsForExpires.Design constraint
safe-outputs.report-failure-as-issuedefaults totrue, so treating the implicit 168-hour default as an unconditional maintenance trigger would generateagentics-maintenance.ymlfor essentially every repository with a gh-aw workflow:safe_outputs_config_types.gomaintenance_workflow.goalready avoids requiring maintenance for implicit no-op reporting.The fix should preserve that opt-in posture rather than merely making action-failure expiry another always-on trigger.
Suggested implementation plan
maintenance.action_failure_issue_expireswas not explicitly configured, suppress the failure-issue expiration marker. The runtime parser may need an explicit disabled value rather than falling back to 168 hours.maintenance.action_failure_issue_expiresvalue as an opt-in to enforceable expiration: generate maintenance and include that value when selecting the minimum cleanup interval.failure-issue-repoand side-repository maintenance so cleanup runs against the repository where failure issues are created; side-repository workflows do not repair missing cleanup in the primary repository.Impact
This is an issue-lifecycle/cleanup defect, not a credential or code-execution vulnerability. It can leave stale failure-report issues open and allow additional reports to accumulate after their displayed expiry.