-
Notifications
You must be signed in to change notification settings - Fork 278
Description
Safe Outputs Audit (Consistency, Overlap, Gaps)
Date: 2026-02-20
Scope and sources
This audit reviews built-in safe output options across:
- User-facing reference docs:
docs/src/content/docs/reference/safe-outputs.md - Type declaration surface:
actions/setup/js/types/safe-outputs-config.d.ts - Runtime parsing/config behavior in workflow compiler:
pkg/workflow/create_issue.gopkg/workflow/create_pull_request.gopkg/workflow/assign_to_agent.gopkg/workflow/close_entity_helpers.gopkg/workflow/update_entity_helpers.gopkg/workflow/safe_output_validation_config.go
1) Consistency review
1.1 Option naming is mostly consistent, but there are important outliers
A) assign-to-agent naming mismatch across surfaces
- Docs show:
name,model,custom-agent,custom-instructions- Reference:
docs/src/content/docs/reference/safe-outputs.md:1097-1103
- Go parser expects:
name,model,custom-agent,custom-instructions- Reference:
pkg/workflow/assign_to_agent.go:13-16
- Type declaration (
.d.ts) shows:default-agent(notname)- Reference:
actions/setup/js/types/safe-outputs-config.d.ts:220-223
Impact: users and tooling that rely on .d.ts may configure the wrong key.
B) max behavior is inconsistent by output type
- Most outputs support configurable
maxvia common base config. create-pull-requestexplicitly forcesmax = 1regardless of user input.- Reference:
pkg/workflow/create_pull_request.go:273-276 - Docs imply singular behavior, but this hard override differs from the broader “configurable max” pattern used elsewhere.
- Reference:
Impact: user expectations around max are not uniform across similarly “create-*” outputs.
C) Footer option shape differs across related PR-review outputs
submit-pull-request-reviewsupports richer footer modes (always|none|if-body) in type definitions.- Reference:
actions/setup/js/types/safe-outputs-config.d.ts:98-107
- Reference:
- Other outputs frequently expose simple boolean footer (
true/false) in docs/config examples.- References:
docs/src/content/docs/reference/safe-outputs.md:742-752pkg/workflow/create_issue.go:23
- References:
Impact: same conceptual option (“footer control”) has different value models depending on output.
D) Targeting model is consistent in pattern, but uneven in capability
- “Update/close/comment/assignment” outputs commonly use
target(triggering|*|number) + optionaltarget-repo.- Examples in docs:
close-issue:docs/src/content/docs/reference/safe-outputs.md:210-218add-comment:docs/src/content/docs/reference/safe-outputs.md:229-236
- Examples in docs:
- “Create” outputs naturally skip
targetand emphasizetarget-repo(creating new entities).- Example:
create-issuedocs:85-96, structpkg/workflow/create_issue.go:18
- Example:
Assessment: this is mostly logical, but it creates a mental-model split users must learn.
1.2 Internal implementation already recognizes commonality
- Close operations share one generic config type and helper pipeline.
- Reference:
pkg/workflow/close_entity_helpers.go:66-73,:88-121
- Reference:
- Update operations also share a generic helper pipeline.
- Reference:
pkg/workflow/update_entity_helpers.go:86-91,:119-153
- Reference:
Assessment: implementation is DRY; external configuration UX is where most inconsistency remains.
2) Overlap and redundancy
2.1 Clear overlap: close-* family
close-issue, close-pull-request, close-discussion all implement the same core pattern:
- target selection
- max limit
- repo scoping
- optional filters (
required-labels,required-title-prefix, and discussion-specific category)
Reference: shared model in pkg/workflow/close_entity_helpers.go:66-73.
Interpretation: these are intentionally separate tools, but semantically one “close entity” capability.
2.2 Clear overlap: update-* family
update-issue, update-pull-request, update-discussion share:
- target selection
- max limit
- selective field enablement
- similar update semantics
Reference: pkg/workflow/update_entity_helpers.go:119-153, :196-257.
Interpretation: same base behavior split by entity-specific fields.
2.3 Partial overlap: comment minimization
add-commentsupportshide-older-comments+allowed-reasons.- Reference:
docs/src/content/docs/reference/safe-outputs.md:235-242
- Reference:
hide-commentseparately supports explicit hide operations.- Reference:
docs/src/content/docs/reference/safe-outputs.md:257-266
- Reference:
Interpretation: two ways to accomplish “reduce comment noise” (automatic side-effect vs explicit operation).
2.4 Partial overlap: agent assignment paths
assign-to-agentfor existing issue/PR automation.create-issuecan assigncopilotdirectly viaassignees.- Reference note in docs:
docs/src/content/docs/reference/safe-outputs.md:1135
- Reference note in docs:
Interpretation: valid but overlapping pathways for similar outcome.
3) Missing safe outputs (likely user demand)
The current catalog is broad, but some common workflows still require custom jobs.
3.1 Explicit non-goal: merge pull request
No built-in merge safe output was found in docs/types/parser surfaces, and that should remain intentional for now to keep a human in the loop for merges.
- No
merge-pull-requestmatch in:docs/src/content/docs/reference/safe-outputs.mdpkg/workflow/*.goactions/setup/js/types/safe-outputs-config.d.ts
Assessment: keep this as a deliberate boundary, not a gap.
3.2 Missing: reopen operations
No reopen-issue, reopen-pull-request, or reopen-discussion safe outputs found (search returned no matches).
Why it matters: close operations exist; lifecycle symmetry is incomplete without reopen.
3.3 Missing: remove reviewer
add-reviewerexists.- No
remove-reviewerfound.
Why it matters: reviewer lifecycle management is one-directional today.
3.4 Missing: reaction operations
No first-class add/remove reaction safe output found.
Why it matters: reactions are a low-risk/high-signal action often used for lightweight triage and acknowledgments.
4) Recommended actions (with backward-compatibility assessment)
Each action below is scoped so another engineer can pick it up directly.
Action 1: Resolve assign-to-agent key mismatch (name vs default-agent)
Problem: docs/parser use name; .d.ts advertises default-agent.
Execution plan:
- Update
actions/setup/js/types/safe-outputs-config.d.tsto usename. - If
default-agentis currently accepted anywhere, keep it as an alias for one deprecation cycle and log a warning. - Add/adjust tests covering config parsing and type surface consistency.
- Update docs examples to show canonical
nameonly.
Files to touch:
actions/setup/js/types/safe-outputs-config.d.tspkg/workflow/assign_to_agent.go(only if alias support needed)docs/src/content/docs/reference/safe-outputs.md- related tests in
pkg/workflow/*assign*test*and JS type/config tests
Acceptance criteria:
nameis canonical in docs/types/parser.- Existing workflows using prior key continue to work (or fail with explicit migration error, per chosen strategy).
Backward-compatibility assessment:
Low risk if alias support is added; medium risk if changed as a hard break. Recommended: support both for one release, then remove alias.
Action 2: Publish an option taxonomy and conformance matrix
Problem: options are conceptually similar but not uniformly documented.
Execution plan:
- Add a matrix section to
safe-outputs.mdwith columns:- targeting (
target), - repo scope (
target-repo,allowed-repos), - filters (
required-*,allowed-*,blocked), - limits (
max, fixed max), - fallback behavior.
- targeting (
- Add a small CI/conformance check (or extend existing script/tests) to ensure docs and config surfaces stay aligned.
Files to touch:
docs/src/content/docs/reference/safe-outputs.mdscripts/check-safe-outputs-conformance.sh(or equivalent conformance tests)
Acceptance criteria:
- A single table lets users compare option support across all safe outputs.
- CI fails when key naming drifts across docs/types/implementation.
Backward-compatibility assessment:
No runtime risk; documentation and validation-only improvement.
Action 3: Normalize footer semantics
Problem: footer supports richer enum modes in some paths and boolean-only in others.
Execution plan:
- Choose one model:
- Preferred: support enum (
always|none|if-body) + boolean aliases globally.
- Preferred: support enum (
- Update config types and parsers to accept chosen model consistently.
- Normalize runtime behavior and environment-variable mapping.
- Add cross-output tests for
true/false/always/none/if-body.
Files to touch:
actions/setup/js/types/safe-outputs-config.d.ts- relevant parser files in
pkg/workflow/* - footer behavior docs in
docs/src/content/docs/reference/safe-outputs.md
Acceptance criteria:
- Same footer values produce equivalent behavior across supported outputs.
- Migration guidance exists for any changed values.
Backward-compatibility assessment:
Medium risk unless boolean aliases are preserved. Recommended: keep booleans as aliases indefinitely.
Action 4: Clarify and enforce max contract per type
Problem: users may assume max always applies, but some types force fixed limits (e.g., create-pull-request).
Execution plan:
- Add “Max behavior” row per type in docs (
configurable,fixed,unbounded). - In parser/validator, reject invalid
maxsettings for fixed-limit types with explicit errors, or ignore with warning (choose one policy). - Add tests to assert behavior.
Files to touch:
docs/src/content/docs/reference/safe-outputs.mdpkg/workflow/create_pull_request.gopkg/workflow/safe_output_validation_config.go- tests around max validation/parse behavior
Acceptance criteria:
- Users can tell at a glance whether
maxis configurable. - Invalid
maxusage yields deterministic behavior and clear messaging.
Backward-compatibility assessment:
Low risk for docs-only clarification; medium risk for parser enforcement if workflows currently rely on silent ignore. Recommended: warn first, enforce in later release.
Action 5: Add lifecycle-completeness outputs (excluding merge)
Problem: lifecycle coverage is asymmetric.
Candidate outputs:
reopen-issuereopen-pull-requestreopen-discussionremove-reviewer- optional:
add-reaction/remove-reaction
Execution plan:
- Define schema/types + frontmatter options for each new output.
- Add parser wiring in
safe_outputs_config.goand config structs. - Implement handlers/jobs with minimal required permissions.
- Document examples and limits in
safe-outputs.md. - Add tests: parse, validation, permission, end-to-end compile snapshots.
Files to touch:
actions/setup/js/types/safe-outputs-config.d.tspkg/workflow/safe_outputs_config.go- new/updated files under
pkg/workflow/* docs/src/content/docs/reference/safe-outputs.md- corresponding test files
Acceptance criteria:
- New outputs compile, validate, and execute with least-privilege permissions.
- No merge-safe-output is introduced.
Backward-compatibility assessment:
Low risk (additive features). Ensure no collisions with existing tool names and defaults remain unchanged.
5) Quick examples
Example A: Key mismatch risk (assign-to-agent)
safe-outputs:
assign-to-agent:
name: "copilot" # works in docs/parserBut .d.ts currently advertises default-agent, which can mislead typed config generators.
Example B: Surprising max behavior
safe-outputs:
create-pull-request:
max: 5 # ignored; runtime forces max=1Reference: pkg/workflow/create_pull_request.go:273-276.