Repository navigation
Add safe-output identifiers and dependency failure propagation - #74376
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot make the safe output result identifier shorter |
|
🧠 Matt Pocock Skills Reviewer is reviewing this pull request using Matt Pocock's engineering skills... |
|
🔎 PR Code Quality Reviewer is reviewing code quality for this pull request... |
|
🔍 Design Decision Gate 🏗️ is checking for design decision records on this pull request... |
|
🔬 Test Quality Sentinel is analyzing test quality on this pull request... |
|
✂️ Ponytail Reviewer has started processing this pull request |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical defects break deployed server startup and ordinary ledger finalization, while dependency gating can allow mutations before prerequisites succeed.
8 open issues
Prevent delegated and standalone outputs from satisfying dependencies · New Strip output_id before ledger transaction normalization · New Include safe_output_submission.cjs in deployment packaging · New Reject dependencies for the memory-staging handler · New Reject only dependency edges that participate in a cycle · New Retry deferred consumers after prerequisite IDs resolve · New Reject reserved dependency-name conflicts in tool schemas · New Reject dependencies for out-of-band diagnostic outputs · New
What changed in this PR
Adds operation-level identifiers and prerequisite checks to gh-aw’s safe-output pipeline, allowing queued operations to reference earlier calls independently of resource temporary IDs.
Changes:
- Adds
output_idgeneration anddepends-onmetadata across submission, ingestion, and outcomes. - Introduces dependency ordering and failure propagation alongside existing temporary-ID handling.
- Updates tool schemas, custom-job configuration, documentation, and regression tests.
| File | Description |
|---|---|
pkg/workflow/safe_outputs_config_generation.go |
Marks separate custom jobs as dependency-unsupported. |
pkg/workflow/safe_outputs_config_generation_test.go |
Tests custom-job capability configuration. |
docs/src/content/docs/reference/safe-outputs.md |
Documents identifiers, dependencies, and execution boundaries. |
docs/public/schemas/unified-session.schema.json |
Adds output IDs to session outcome schemas. |
actions/setup/js/types/unified_session.d.ts |
Types output IDs in safe-output data. |
actions/setup/js/safe_outputs_tools_loader.cjs |
Integrates dependency schemas and submission tracking. |
actions/setup/js/safe_outputs_mcp_wrapped_arguments.test.cjs |
Tests dependency aliases and returned IDs. |
actions/setup/js/safe_outputs_mcp_arguments.cjs |
Preserves wrapped dependencies and rejects conflicting aliases. |
actions/setup/js/safe_outputs_handlers.test.cjs |
Updates handler assertions for generated IDs. |
actions/setup/js/safe_outputs_handlers.cjs |
Wraps handlers with submission tracking. |
actions/setup/js/safe_output_type_validator.test.cjs |
Tests metadata validation and unsupported dependencies. |
actions/setup/js/safe_output_type_validator.cjs |
Validates and preserves submission metadata. |
actions/setup/js/safe_output_submission.test.cjs |
Tests submission tracking and pipeline integration. |
actions/setup/js/safe_output_submission.cjs |
Implements identifier generation and dependency metadata handling. |
actions/setup/js/safe_output_routing_parity.test.cjs |
Updates routing assertions for output IDs. |
actions/setup/js/safe_output_outcomes.cjs |
Preserves IDs and dependency error codes in outcomes. |
actions/setup/js/safe_output_handler_manager.cjs |
Integrates dependency gating with execution and retries. |
actions/setup/js/safe_output_dependencies.test.cjs |
Tests ordering, propagation, cycles, and outcome confirmation. |
actions/setup/js/safe_output_dependencies.cjs |
Implements dependency planning and prerequisite checks. |
actions/setup/js/safe_output_action_handler.test.cjs |
Tests exclusion of protocol metadata from action inputs. |
actions/setup/js/safe_output_action_handler.cjs |
Filters identifier and dependency fields from action payloads. |
actions/setup/js/generate_safe_outputs_tools.test.cjs |
Tests generated dependency schemas. |
actions/setup/js/generate_safe_outputs_tools.cjs |
Adds dependency parameters to generated tools. |
actions/setup/js/collect_ndjson_output.test.cjs |
Tests custom-output metadata ingestion. |
actions/setup/js/collect_ndjson_output.cjs |
Preserves metadata and rejects unsupported custom-job dependencies. |
.github/workflows/smoke-copilot.lock.yml |
Updates custom-job dependency capability configuration. |
.github/workflows/smoke-copilot-arm.lock.yml |
Updates custom-job dependency capability configuration. |
.github/workflows/smoke-copilot-aoai-entra.lock.yml |
Updates custom-job dependency capability configuration. |
.github/workflows/smoke-copilot-aoai-apikey.lock.yml |
Updates custom-job dependency capability configuration. |
.github/workflows/mcp-inspector.lock.yml |
Marks its Slack job as dependency-unsupported. |
.github/workflows/daily-choice-test.lock.yml |
Marks its custom test job as dependency-unsupported. |
.github/workflows/aw-issue-clustering.lock.yml |
Marks its publishing job as dependency-unsupported. |
Review effort: Max (auto)
| */ | ||
| function isConfirmedDependencySuccess(record) { | ||
| if (process.env.GH_AW_SAFE_OUTPUTS_STAGED === "true") return false; | ||
| if (!record || record.success !== true || classifySafeOutputResult(record) !== "success") return false; |
There was a problem hiding this comment.
Already addressed in 79b9021: delegated effects cannot confirm prerequisite success, and standalone noop/upload_asset dependencies are rejected. Regression tests exercise the real handlers.
| const outputId = `so_${randomUUID()}`; | ||
| const recorded = { ...entry, output_id: outputId }; |
There was a problem hiding this comment.
Fixed in 79b9021: ledger append finalization strips output_id and dependency metadata before transaction normalization, with submission-to-finalization regression coverage.
| const { clearValidationMarker, formatJSONFiles, runCustomMemoryValidation, writeValidationMarker } = require("./memory_custom_validation.cjs"); | ||
| const { compileFileGlobPatterns, isMemoryFileEligible } = require("./memory_file_eligibility.cjs"); | ||
| const { normalizeRuntimeMessage, readClaimScopeContext, withClaimExecution, currentClaimHandle, claimArtifactPath } = require("./work_queue_claim_scope.cjs"); | ||
| const { createSubmissionTracker } = require("./safe_output_submission.cjs"); |
There was a problem hiding this comment.
Fixed in 47eb33b: safe_output_submission.cjs is included in SAFE_OUTPUTS_FILES for deployed safe-output packaging.
| const cyclic = order.length !== messages.length; | ||
| const visited = new Set(order); | ||
| messages.forEach((message, index) => { | ||
| if (!visited.has(index)) { | ||
| // Preserve the legacy cycle fallback only for messages without explicit edges. | ||
| if (message["depends-on"] !== undefined || message.depends_on !== undefined) invalid.set(index, "Cyclic safe-output dependency"); | ||
| order.push(index); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Fixed in 79b9021: cycle detection now invalidates an explicit dependency only when its edge participates in a cycle; a downstream consumer is covered by regression tests.
| } finally { | ||
| // Release newly ready producers before the next legacy temporary-ID | ||
| // retry; it may need an ID created by a previously waiting output. | ||
| await drainWaitingMessages(); |
There was a problem hiding this comment.
Fixed in 79b9021: deferred consumers are retried in bounded, progress-aware rounds when newly resolved IDs become available, without replaying completed mutations.
| function addDependencySchema(tool) { | ||
| tool.inputSchema ||= { type: "object" }; | ||
| tool.inputSchema.properties ||= {}; | ||
| tool.inputSchema.properties["depends-on"] = { | ||
| description: "One output_id, or a nonempty array of output_id values returned by earlier safe-output calls. Execute only after every prerequisite succeeds; otherwise this output fails. These are not temporary resource IDs.", | ||
| "x-synonyms": ["depends_on"], | ||
| oneOf: [ | ||
| { type: "string", pattern: OUTPUT_ID_PATTERN }, | ||
| { type: "array", minItems: 1, uniqueItems: true, items: { type: "string", pattern: OUTPUT_ID_PATTERN } }, | ||
| ], | ||
| }; | ||
| } |
There was a problem hiding this comment.
Already handled in the current submission schema: reserved depends-on, depends_on, and output_id inputs are rejected, while repeated dependency-schema injection is idempotent. Regression coverage is in safe_output_submission.test.cjs.
| if ((item["depends-on"] !== undefined || item.depends_on !== undefined) && ["upload_asset", "noop"].includes(itemType)) { | ||
| return { isValid: false, error: `Line ${lineNum}: depends-on is not supported for ${itemType}, which executes outside the safe-output handler manager.` }; | ||
| } |
There was a problem hiding this comment.
Fixed in 79b9021: dependencies are rejected for report_incomplete, report_missing_tool, and report_missing_data at submission, preventing their out-of-band consumers from bypassing dependency gating.
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Shortened IDs to 22 URL-safe characters while retaining UUID entropy. Commit: |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot merge main and recompile |
…utputs-identifier Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Merged the latest |
|
Commit pushed:
|
PR finisher
PR finisher dispatch requested for the following outstanding work: merge main; dispatch delegated-effects review threads.
|
|
PR finisher: the dispatch fix ( Sous-chef head: f88868b
|
|
🎉 This pull request is included in a new release. Release: |
…forks flag Document safe-output output_id/depends-on dependency gating (#74376), the managed source-sha frontmatter field (#74948), the dangerously-allow-pull-request-target-forks-all feature flag (#74884), and detection report-as-issue permission requirements (#74949). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>


Safe-output calls need operation identifiers that subsequent calls can reference through
depends-on. Dependent operations must fail without executing when a prerequisite fails.output_id(so_<UUID>), distinct from resourcetemporary_idvalues, and retain it through ingestion and execution outcomes.upload_asset, andnoopreject dependent requests; delegated effects cannot establish prerequisite success.A subsequent
add_commentcall can reference a previously returned identifier:{ "item_number": 123, "body": "The prerequisite update completed.", "depends-on": "so_4a1f2c30-1b2c-4d5e-8f90-123456789abc" }