Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
7d4a1d7
feat(compile): add Conclusion job for pipeline failure reporting
jamesadevine Jun 17, 2026
9f6a937
fix: update execute tests for simplified noop/missing-tool and fix cr…
jamesadevine Jun 17, 2026
bb4f826
fix(compile): address PR review feedback for conclusion job
jamesadevine Jun 17, 2026
f9dd75d
refactor(compile): move conclusion config under safe-outputs, add fla…
jamesadevine Jun 17, 2026
8b43695
fix(compile): use SC_WRITE_TOKEN in Conclusion job when write SC is c…
jamesadevine Jun 17, 2026
efe09d0
fix(compile): address second PR review — 4 correctness bugs
jamesadevine Jun 17, 2026
21034be
refactor(compile): replace JSON blob env vars with flat per-field vars
jamesadevine Jun 18, 2026
546a30c
fix(compile): fix SC_WRITE_TOKEN double-wrap, stale docs, remove chec…
jamesadevine Jun 18, 2026
8279b93
fix(ir): reject special characters in AdoMacro names at lowering
jamesadevine Jun 18, 2026
86e1191
fix: address review — titlePrefix placeholder support, boolean env va…
jamesadevine Jun 18, 2026
390036f
fix(compile): bash guard for missing node, deduplicate comment, clari…
jamesadevine Jun 18, 2026
8d65fa6
fix(compile): copy executed NDJSON to safe_outputs artifact, hoist Jo…
jamesadevine Jun 18, 2026
f4aacf7
fix(compile): copy NDJSON manifest to artifact, guard conclusion.js, …
jamesadevine Jun 18, 2026
b2abdb8
fix(compile): accept report-failure-as-work-item global config key
jamesadevine Jun 18, 2026
623d410
fix(compile): reuse supply-chain-aware ado-script download in Conclus…
jamesadevine Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,20 @@ jobs:
run: |
set -euo pipefail
cd scripts
zip -r ../ado-script.zip ado-script/gate.js ado-script/import.js ado-script/exec-context-pr.js ado-script/exec-context-pr-synth.js ado-script/exec-context-manual.js ado-script/exec-context-pipeline.js ado-script/exec-context-ci-push.js ado-script/exec-context-workitem.js ado-script/exec-context-schedule.js ado-script/exec-context-pr-checks.js ado-script/exec-context-repo.js
# Auto-bundle every ncc output at the ado-script root. `npm run build`
# emits exactly one <name>.js per src/<name>/ bundle directory (all
# source is .ts under src/), so globbing *.js captures every bundle
# automatically — no manual per-bundle list to keep in sync. The
# ado-script-bundle-coverage test guards that every bundle dir is
# actually built.
shopt -s nullglob
bundles=(ado-script/*.js)
if [ ${#bundles[@]} -eq 0 ]; then
echo "ERROR: no ado-script bundles found — did 'npm run build' run?" >&2
exit 1
fi
echo "Bundling ${#bundles[@]} ado-script file(s): ${bundles[*]}"
zip -r ../ado-script.zip "${bundles[@]}"

- name: Upload release assets
env:
Expand Down
14 changes: 11 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Every compiled pipeline runs as three sequential jobs:
│ ├── compile/ # Pipeline compilation module
│ │ ├── mod.rs # Module entry point and Compiler trait
│ │ ├── common.rs # Shared helpers across targets
│ │ ├── agentic_pipeline.rs # Canonical Setup → Agent → Detection → SafeOutputs → Teardown shape (shared by every target); BuiltPipelineContext, build_pipeline_context, build_canonical_jobs, per-job builders, fold_agent_conditions, agent_job_variables_hoist
│ │ ├── agentic_pipeline.rs # Canonical Setup → Agent → Detection → SafeOutputs → Teardown → Conclusion shape (Conclusion emitted when configured; shared by every target); BuiltPipelineContext, build_pipeline_context, build_canonical_jobs, per-job builders, fold_agent_conditions, agent_job_variables_hoist
│ │ ├── ir/ # Typed Azure DevOps pipeline IR
│ │ │ ├── mod.rs # IR module entry point and shared types
│ │ │ ├── ids.rs # Stable IDs for jobs/steps/outputs in the IR
Expand Down Expand Up @@ -235,12 +235,15 @@ Every compiled pipeline runs as three sequential jobs:
│ ├── update-ado-agentic-workflow.md # Guide for modifying an existing agentic pipeline
│ └── debug-ado-agentic-workflow.md # Guide for troubleshooting a failing agentic pipeline
├── scripts/ # Supporting scripts shipped as release artifacts
│ └── ado-script/ # TypeScript workspace for bundled gate.js, import.js, exec-context-pr.js, exec-context-pr-synth.js
│ └── ado-script/ # TypeScript workspace for bundled runtime helpers (gate.js, import.js, exec-context-*.js, conclusion.js)
│ └── src/
│ ├── gate/ # Gate evaluator source (bundled to gate.js)
│ ├── import/ # Runtime prompt resolver source (bundled to import.js)
│ ├── exec-context-pr/ # PR-context precompute source (bundled to exec-context-pr.js)
│ ├── exec-context-pr-synth/ # Synthetic-PR resolver source (bundled to exec-context-pr-synth.js)
│ ├── exec-context-manual/ # Manual-run context source (bundled to exec-context-manual.js)
│ ├── exec-context-pipeline/ # Pipeline-completion context source (bundled to exec-context-pipeline.js)
│ ├── conclusion/ # Conclusion-job reporter source (bundled to conclusion.js)
│ └── shared/ # Shared modules across bundles (auth, ado-client, env-facts, types.gen.ts)
├── tests/ # Integration tests and fixtures
├── docs/ # Per-concept reference documentation (see index below)
Expand Down Expand Up @@ -286,6 +289,9 @@ index to jump to the right page.
`command`).
- [`docs/parameters.md`](docs/parameters.md) — ADO runtime parameters surfaced
in the pipeline UI, including the auto-injected `clearMemory` parameter.
- [`docs/conclusion.md`](docs/conclusion.md) — `conclusion:` configuration for
the always-running post-pipeline housekeeping job that files work-item
reports for failures and diagnostic signals.
- [`docs/tools.md`](docs/tools.md) — `tools:` configuration (bash allow-list,
`edit`, `cache-memory`, `azure-devops` MCP).
- [`docs/runtimes.md`](docs/runtimes.md) — `runtimes:` configuration (Lean 4,
Expand Down Expand Up @@ -348,7 +354,9 @@ index to jump to the right page.
adding codemods.
- [`docs/ado-script.md`](docs/ado-script.md) — `ado-script` workspace
(`scripts/ado-script/`): the bundled TypeScript runtime helpers (today:
`gate.js`, `import.js`, `exec-context-pr.js`, `exec-context-pr-synth.js`), schemars-driven type codegen, and the A2 design decision.
`gate.js`, `import.js`, `exec-context-pr.js`, `exec-context-pr-synth.js`,
`exec-context-manual.js`, `exec-context-pipeline.js`, `conclusion.js`),
schemars-driven type codegen, and the A2 design decision.
- [`docs/local-development.md`](docs/local-development.md) — local development
setup notes.

Expand Down
21 changes: 15 additions & 6 deletions docs/ado-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
`ado-script` is the umbrella name for the TypeScript workspace at
[`scripts/ado-script/`](../scripts/ado-script/). It produces small,
ncc-bundled Node programs that the **compiler injects into every emitted
pipeline** as runtime helpers. Today it produces four bundles:
pipeline** as runtime helpers. Today it produces seven bundles:

- `gate.js` — trigger-filter gate evaluator (Setup job).
- `import.js` — runtime prompt resolver described in
Expand All @@ -26,6 +26,10 @@ pipeline** as runtime helpers. Today it produces four bundles:
`aw-context/pipeline/upstream-*` files plus a `## Pipeline-completion
context` prompt fragment (Agent job; see
[`execution-context.md`](execution-context.md)).
- `conclusion.js` — Conclusion job work-item reporter: reads the
safe-outputs execution manifest and upstream job results,
files/comments ADO work items for pipeline failures and diagnostic
signals (Conclusion job).

> **Internal-only.** `ado-script` is not a user-facing front-matter
> feature. Authors never write an `ado-script:` block in their agent
Expand Down Expand Up @@ -381,16 +385,20 @@ scripts/ado-script/
│ ├── exec-context-manual/ # exec-context-manual.js entry point + manual-context precompute
│ │ ├── index.ts # main(): collect PARAM_* env vars → JSON snapshot → prompt fragment
│ │ └── __tests__/ # unit tests for success / failure / sanitisation paths
│ └── exec-context-pipeline/ # exec-context-pipeline.js entry point + pipeline-completion precompute
│ ├── index.ts # main(): validate TriggeredBy ids → fetch upstream Build via REST → stage + prompt
│ └── __tests__/ # unit tests for validate / success / failure / sanitisation paths
│ ├── exec-context-pipeline/ # exec-context-pipeline.js entry point + pipeline-completion precompute
│ │ ├── index.ts # main(): validate TriggeredBy ids → fetch upstream Build via REST → stage + prompt
│ │ └── __tests__/ # unit tests for validate / success / failure / sanitisation paths
│ └── conclusion/ # conclusion.js entry point + Conclusion-job reporter
│ ├── index.ts # main(): inspect upstream results + safe-outputs manifest → file/append work items
│ └── __tests__/ # unit tests for signal detection and work-item filing behaviour
├── test/ # End-to-end smoke tests (gate, import, exec-context-pr)
├── gate.js # ncc bundle output (gitignored)
├── import.js # ncc bundle output (gitignored)
├── exec-context-pr.js # ncc bundle output (gitignored)
├── exec-context-pr-synth.js # ncc bundle output (gitignored)
├── exec-context-manual.js # ncc bundle output (gitignored)
└── exec-context-pipeline.js # ncc bundle output (gitignored)
├── exec-context-pipeline.js # ncc bundle output (gitignored)
└── conclusion.js # ncc bundle output (gitignored)
```

The release workflow (`.github/workflows/release.yml`) runs
Expand All @@ -399,7 +407,8 @@ The release workflow (`.github/workflows/release.yml`) runs
`scripts/ado-script/exec-context-pr.js`,
`scripts/ado-script/exec-context-pr-synth.js`,
`scripts/ado-script/exec-context-manual.js`, and
`scripts/ado-script/exec-context-pipeline.js` into the
`scripts/ado-script/exec-context-pipeline.js`, and
`scripts/ado-script/conclusion.js` into the
`ado-script.zip` release asset. Pipelines download that asset at
runtime by URL pinned to the compiler's `CARGO_PKG_VERSION`, verify
its SHA-256 against the `checksums.txt` asset, then extract.
Expand Down
2 changes: 1 addition & 1 deletion docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,6 @@ These commands are not shown in `--help` but are available for contributors work

## Pipeline IR Reference

The compiler builds typed Azure DevOps pipeline IR and lowers it through one YAML emitter. The canonical Setup → Agent → Detection → SafeOutputs → Teardown shape lives in `agentic_pipeline.rs` (shared by every target); target-specific builders (`standalone_ir.rs`, `onees_ir.rs`, `job_ir.rs`, and `stage_ir.rs`) own only the per-target envelope (pipeline shape, template parameters, 1ES wrapping).
The compiler builds typed Azure DevOps pipeline IR and lowers it through one YAML emitter. The canonical Setup → Agent → Detection → SafeOutputs → Teardown shape, plus the optional always-running Conclusion job when `conclusion:` is configured, lives in `agentic_pipeline.rs` (shared by every target); target-specific builders (`standalone_ir.rs`, `onees_ir.rs`, `job_ir.rs`, and `stage_ir.rs`) own only the per-target envelope (pipeline shape, template parameters, 1ES wrapping).

See [`docs/ir.md`](ir.md) for the complete IR reference.
111 changes: 111 additions & 0 deletions docs/conclusion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Conclusion Job

_Part of the [ado-aw documentation](../AGENTS.md)._

The Conclusion job is an always-running housekeeping job that reports
pipeline failures and diagnostic signals (`noop`, `missing-tool`,
`missing-data`) to Azure DevOps work items.

## When it runs

The compiler emits the Conclusion job whenever `safe-outputs:` is
configured in front matter (noop is always on, so the conclusion job
runs for every pipeline that has safe outputs). The job runs with
`condition: always()`, regardless of upstream job outcomes.

## Pipeline shape

```text
Setup → Agent → Detection → SafeOutputs → Teardown → Conclusion
condition: always()
```

## Configuration

All configuration lives under `safe-outputs:` in front matter.

### Global toggle

```yaml
safe-outputs:
report-failure-as-work-item: false # disable all failure work-item filing
```

### Per-tool configuration

Each diagnostic tool (`noop`, `missing-tool`, `missing-data`) supports
these fields under its `safe-outputs:` entry:

| Field | Type | Default | Notes |
|---|---|---|---|
| `report-as-work-item` | bool | `true` | Per-tool opt-out for work-item filing. |
| `title-prefix` | string | _built-in per signal_ | Prefix for the work-item title. |
| `work-item-type` | string | `"Task"` | Work item type to create. |
| `area-path` | string | _none_ | Azure DevOps area path. |
| `iteration-path` | string | _none_ | Azure DevOps iteration path. |
| `tags` | list of strings | `[]` | Static tags applied to created work items. |

### Example

```yaml
safe-outputs:
noop:
title-prefix: "[ado-aw] Agent noop"
work-item-type: Task
area-path: "MyProject\\MyTeam"
tags:
- agent-noop
missing-tool:
report-as-work-item: false # don't file WIs for missing tools
missing-data: {} # use defaults
```

### Disabling a tool entirely

Setting a tool to `false` prevents the agent from calling it and
disables work-item filing:

```yaml
safe-outputs:
noop: false
```

## What gets reported

- **Pipeline failure** — when the Agent, Detection, or SafeOutputs job
fails.
- **Noop** — when the agent produced noop safe outputs.
- **Missing tool** — when the agent reported missing tools.
- **Missing data** — when the agent reported missing data.

## How it works

The job downloads the `safe_outputs` artifact, reads
`safe-outputs-executed.ndjson`, checks upstream Agent / Detection /
SafeOutputs job results, and then files or comments on Azure DevOps
work items using `SYSTEM_ACCESSTOKEN`.

Per-tool config is passed from the compiler to `conclusion.js` as
individual flat env vars per field (e.g. `AW_NOOP_TITLE_PREFIX`,
`AW_NOOP_AREA_PATH`), matching gh-aw's pattern.

## Deduplication

Conclusion reports deduplicate by rendered work-item title. The job
searches for an existing open work item with the same title; if it finds
one, it appends a comment. Otherwise it creates a new work item.

## Relationship to gh-aw

This mirrors gh-aw's conclusion-job pattern: a single always-running
post-pipeline job handles housekeeping after the main agentic flow.

## Security

The Conclusion job uses `SYSTEM_ACCESSTOKEN` (or `SC_WRITE_TOKEN` when
a write service connection is configured) only inside the post-pipeline
reporter. It works from compiler-controlled `safe-outputs:`
configuration plus the sanitized `safe-outputs-executed.ndjson`
execution manifest rather than giving raw agent prompt content direct
work-item API access.
2 changes: 1 addition & 1 deletion docs/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ado-aw compiles agent markdown into Azure DevOps YAML through the typed pipeline
When extending the compiler:

1. **New CLI commands**: add variants to the `Commands` enum in `src/main.rs`, implement dispatch, and add parsing/behavior tests.
2. **New compile targets**: build a typed `Pipeline` IR in a target wrapper module under `src/compile/` (use existing `standalone_ir.rs`, `onees_ir.rs`, `job_ir.rs`, and `stage_ir.rs` as references). The canonical 5-job shape itself lives in `src/compile/agentic_pipeline.rs` and is reused by every target — wrappers only set the per-target `PipelineShape` and lift the shared `BuiltPipelineContext` into the right envelope.
2. **New compile targets**: build a typed `Pipeline` IR in a target wrapper module under `src/compile/` (use existing `standalone_ir.rs`, `onees_ir.rs`, `job_ir.rs`, and `stage_ir.rs` as references). The canonical Setup → Agent → Detection → SafeOutputs → Teardown shape, plus the optional Conclusion job, lives in `src/compile/agentic_pipeline.rs` and is reused by every target — wrappers only set the per-target `PipelineShape` and lift the shared `BuiltPipelineContext` into the right envelope.
3. **New front matter fields**: add fields to `FrontMatter` or nested config types in `src/compile/types.rs`. Breaking changes require a codemod under `src/compile/codemods/`; see [`docs/codemods.md`](codemods.md).
4. **New compiler extensions**: implement the `CompilerExtension` `name` / `phase` / `declarations` trio and return typed `Declarations`.
5. **New safe-output tools**: add to `src/safeoutputs/`, implement the safe-output data model and executor, and register it in MCP and Stage 3 execution wiring.
Expand Down
6 changes: 5 additions & 1 deletion docs/front-matter.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ parameters: # optional ADO runtime parameters (surfaced in UI
default: false
---

Additional top-level field reference:

- The always-running Conclusion job (pipeline failure / diagnostic
signal reporting) is triggered automatically when `safe-outputs:` is
configured. See [docs/conclusion.md](conclusion.md).

## Build and Test

Expand Down Expand Up @@ -428,4 +433,3 @@ pipeline. In this mode the compiler:

Result: every PR update fires exactly one PR-typed build (`Build.Reason
== PullRequest`); commit-driven CI is fully silenced.

4 changes: 2 additions & 2 deletions docs/ir.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ _Part of the [ado-aw documentation](../AGENTS.md)._

ado-aw no longer compiles pipelines by substituting strings into YAML template files. Every production target builds a typed Azure DevOps pipeline IR, resolves graph-level facts, lowers that IR to `serde_yaml::Value`, and serializes once with `serde_yaml::to_string`.

The implementation lives under `src/compile/ir/`. The canonical 5-job agentic-pipeline shape (Setup → Agent → Detection → SafeOutputs → Teardown) lives in `src/compile/agentic_pipeline.rs` and is shared by every target. Per-target wrappers handle only the envelope:
The implementation lives under `src/compile/ir/`. The canonical agentic-pipeline shape (Setup → Agent → Detection → SafeOutputs → Teardown, plus an optional always-running Conclusion job when `conclusion:` is configured) lives in `src/compile/agentic_pipeline.rs` and is shared by every target. Per-target wrappers handle only the envelope:

- `src/compile/standalone_ir.rs`
- `src/compile/onees_ir.rs`
Expand Down Expand Up @@ -261,7 +261,7 @@ The production target wrappers are:
- `job_ir.rs` — wraps the canonical shape as a target-job template with external `dependsOn` / `condition` template parameters.
- `stage_ir.rs` — wraps the canonical shape as a target-stage template with the stage-level external-parameter wrapper.

The canonical 5-job Setup → Agent → Detection → SafeOutputs → Teardown shape itself lives in `agentic_pipeline.rs` and is reused unchanged by every wrapper above; extensions plug into it via `Declarations` (steps, env, hosts, MCPG entries, and Agent-job condition clauses — see `Declarations::agent_conditions`).
The canonical Setup → Agent → Detection → SafeOutputs → Teardown shape, plus the optional Conclusion job, lives in `agentic_pipeline.rs` and is reused unchanged by every wrapper above; extensions plug into it via `Declarations` (steps, env, hosts, MCPG entries, and Agent-job condition clauses — see `Declarations::agent_conditions`).

When adding a target, follow the same pattern: parse and validate front matter, collect extension `Declarations`, build typed jobs/stages/steps, set the correct `PipelineShape`, and call the shared emit path.

Expand Down
Loading
Loading