← AZ-400: DevOps from delivery to operations
23 / 26 · 120 MIN

Pipeline operations: events, queues and evidence

Diagnose run selection and reruns, preserve required work and connect artifacts to authorized delivery.

Identify inputs and paths

Before investigating a build, record the run, attempt, commits and paths actually used. In the example, funds was retrieved into s; adding tools without explicit paths moves the repositories into s/funds and s/tools. A publisher still reading s/out can find old output on a reused agent. The problem is not resolved merely because the file exists. Confirm the producer path, consumer path and connection to the intended candidate. Declare self when its files are required alongside another checkout. Use explicit paths when they clarify the contract between steps. workspaceRepo selects the default working directory but neither selects the branch nor merges trees. Retain identifiers needed for diagnosis without printing credentials or sensitive content. Distinguish observed inputs from the values the team intended to use.

Select the revision at the right time

An inline checkout resolves as a resource reference at compile time. Putting $(branch) in the value does not perform the expected macro expansion; the service can look for that literal text. When selection happens while preparing a run, a parameter referenced through a template expression provides an appropriate alternative. This does not authorize every branch: the team remains responsible for restricting choices under its process. Nor should a completion trigger be assumed to carry the same commit across different repositories. Record the application revision and deployment repository revision separately. On GitHub, a relative call to a local workflow uses the caller commit. These are different contracts that should be explicit before attributing a failure to recently changed code. Trace each input to the rule that selected it.

Diagnose the event before looking for an agent

If no run exists, start with filters and the configuration evaluating them. In Azure, editing a completion filter on a feature branch does not automatically change the default-branch version used for evaluation. Trigger tags are cumulative and every selected stage must succeed. For CI, also check interface overrides and Git path capitalization. In Azure Repos, pull-request validation is configured through target-branch policy. A pr block copied from another provider does not establish the intended protection. When two runs appear, compare their reasons: CI and completion may have started distinct work. Decide whether to remove a trigger only after understanding each event’s purpose, so required validation is preserved. Agent capacity becomes relevant after selection, when there is work ready to execute or waiting for a suitable worker.

Distinguish build feedback from delivery waiting

A batched CI run can remain open awaiting deployment approval. In that design, adding agents neither finishes the previous execution nor releases the next batch. If the goal is fast feedback while retaining production approval, separate the flows and carry a verifiable artifact identity between them. The project must define who approves, what they approve and what evidence the decision requires. Do not confuse CI batching with schedule batching: Azure scheduling with always: true can start another execution even with batch: true. A property with the same name does not guarantee identical semantics across different events. Measure queue time, execution time and human waiting separately to select the change addressing the observed delay. Preserve correlation when splitting the workflow so speed does not obscure delivery evidence.

A queue does not represent every business obligation

On GitHub.com, queue: single retains only one pending execution in the group; a new arrival replaces the previous one. cancel-in-progress separately controls the running execution. queue: max permits more pending runs, but has limited capacity and is incompatible with cancel-in-progress: true. Group waiting order can differ from original request order. In the M1, M2 and M3 migration case, the obligation is to apply a sequence with prerequisites. Before advancing M3, confirm actual state and recover the canceled M2 operation. A durable ledger and an executor validating prerequisites can support that design. Increasing queue capacity does not automatically recover lost work. Also define handling for saturation, repetition and partial execution, without assuming cancellation rolls back external workflow actions. The business sequence requires its own evidence.

Interpret reruns, completion and authorization

A GitHub rerun retains GITHUB_SHA, GITHUB_REF and privileges of the actor that triggered the original execution. The person requesting re-run can differ; this does not turn the attempt into an execution at the newest commit or automatically transfer that person’s privileges. Identify the attempt and evidence produced on each rerun. In a flow chained by workflow_run, completed includes failed conclusions. If the agreed rule permits publishing only after success, apply a condition on upstream conclusion in the relevant job. Even that condition does not establish that a particular package corresponds to the accepted run. Correlate the artifact and verify the delivery criterion. Keep questions about completion, technical success, content identity and business authorization separate; each requires its own evidence. Avoid assuming that one green indicator answers all four.

Publish identifiable evidence and preserve it

In a matrix, give artifacts distinct names for each dimension and define how results will be aggregated. Replacing an artifact through overwrite creates another identity, so approval tied to the former ID needs reconciliation. When a report is mandatory, absence must fail the task and reach the acceptance decision; a warning can leave the job green. Also review hidden files: including a necessary manifest does not authorize publishing a credential file in the same directory. After download, handle digest discrepancies under the defined integrity criterion; a warning alone does not enforce rejection. Plan preservation of existing evidence because increasing retention does not retroactively extend old objects. None of these checks by itself turns the package into an approved release. Bind the decision to the exact evidence inspected.

Practise decisions and recognize model limits

This lesson’s script works only with fictional in-memory records. It models selected queue admission rules, cumulative filters and an acceptance criterion requiring particular revisions, attempt, ID and outputs. Mentally change one field before execution and predict which check should fail. The residual-package case shows why finding a ZIP does not prove its origin. The migration case shows why serialization does not guarantee retaining every operation. The script neither interprets YAML nor calls Azure or GitHub, and it runs no migrations. Results demonstrate this model’s behavior and support decision discussion; validating a real platform requires an authorized rehearsal with identified configuration and version. Summarize the decision, missing evidence and acceptable alternative before consulting answers. Use the distinction between model evidence and platform evidence when reporting readiness.

"""Local teaching model. Does not run or emulate Azure/GitHub pipeline engines.
Inputs are fictional records. No filesystem writes, network or credentials.
"""
import json


def enqueue(pending, arrival, mode):
 """Selected documented pending-admission rules; no running cancellation."""
 if mode == 'single':
 return [arrival], list(pending)
 if mode == 'max':
 return (list(pending), [arrival]) if len(pending) >= 100 else (pending + [arrival], [])
 raise ValueError('Unsupported teaching-model mode')


def completion_matches(required_tags, actual_tags, required_stages, outcomes):
 return set(required_tags) <= set(actual_tags) and all(
 outcomes.get(stage) == 'success' for stage in required_stages)


def assess_package(candidate, actual, required_files):
 """Fictional acceptance rule, NOT a vendor-provided guarantee."""
 errors = []
 for key in ['app_commit', 'tools_commit', 'attempt', 'artifact_id']:
 if actual.get(key)!= candidate.get(key):
 errors.append('identity:' + key)
 if not set(required_files) <= set(actual.get('files', [])):
 errors.append('missing-required-output')
 if not actual.get('digest_matches', False):
 errors.append('digest-not-confirmed')
 return errors


def next_migration(expected, applied, requested):
 """Require applied IDs to be an exact prefix; no actual database operations."""
 if applied!= expected[:len(applied)]:
 return 'reconcile'
 remaining = expected[len(applied):]
 if not remaining:
 return 'already-complete'
 return 'eligible' if requested == remaining[0] else 'prerequisite-missing'


def run:
 checks = []
 def check(name, condition):
 if not condition:
 raise AssertionError(name)
 checks.append(name)

 # Explicit fixture from the lesson, not a general Azure path resolver.
 paths = {'funds': 's/funds', 'tools': 's/tools'}
 check('funds path after second checkout', paths['funds'] == 's/funds')
 check('old output path is not current output path', 's/out/package.zip'!= paths['funds'] + '/out/package.zip')
 check('one tag cannot satisfy two tags', not completion_matches(['Signed', 'Production'], ['Signed'], ['Build'], {'Build': 'success'}))
 check('all required tags satisfy tag filter', completion_matches(['Signed', 'Production'], ['Signed', 'Production'], ['Build'], {'Build': 'success'}))
 check('running stage does not satisfy completion', not completion_matches([], [], ['Build', 'PreProd'], {'Build': 'success', 'PreProd': 'running'}))
 check('failed stage does not satisfy completion', not completion_matches([], [], ['Build', 'PreProd'], {'Build': 'success', 'PreProd': 'failure'}))
 check('both successful stages satisfy completion', completion_matches([], [], ['Build', 'PreProd'], {'Build': 'success', 'PreProd': 'success'}))
 check('missing named stage is not success', not completion_matches([], [], ['PreProd'], {}))
 pending, canceled = enqueue(['M2'], 'M3', 'single')
 check('single replaces older pending', pending == ['M3'])
 check('single reports canceled pending', canceled == ['M2'])
 pending, canceled = enqueue(['M2'], 'M3', 'max')
 check('max admits another pending below capacity', pending == ['M2', 'M3'] and canceled == [])
 full = [f'run-{n}' for n in range(100)]
 pending, canceled = enqueue(full, 'extra', 'max')
 check('max rejects arrival at capacity', canceled == ['extra'])
 check('max preserves existing pending at capacity', pending == full)
 check('queue helper does not mutate input', full == [f'run-{n}' for n in range(100)])
 arrivals = [{'id': 'M2', 'dispatched': 1, 'waiting': 8}, {'id': 'M3', 'dispatched': 2, 'waiting': 5}]
 ordered = sorted(arrivals, key=lambda r: r['waiting'])
 check('waiting order can differ from dispatch order', [r['id'] for r in ordered] == ['M3', 'M2'])
 candidate = dict(app_commit='F8', tools_commit='T3', attempt='new', artifact_id=811)
 valid = dict(candidate, files=['package.zip', '.manifest'], digest_matches=True)
 required = ['package.zip', '.manifest']
 check('matching complete evidence accepted by fictional rule', assess_package(candidate, valid, required) == [])
 for key, wrong in [('app_commit', 'F7'), ('tools_commit', 'T2'), ('attempt', 'old'), ('artifact_id', 810)]:
 check('reject wrong ' + key, 'identity:' + key in assess_package(candidate, dict(valid, **{key: wrong}), required))
 check('reject missing manifest', 'missing-required-output' in assess_package(candidate, dict(valid, files=['package.zip']), required))
 check('reject digest warning under fictional acceptance rule', 'digest-not-confirmed' in assess_package(candidate, dict(valid, digest_matches=False), required))
 check('absent digest evidence is not accepted', 'digest-not-confirmed' in assess_package(candidate, {k:v for k,v in valid.items if k!= 'digest_matches'}, required))
 # Deliberate exact allowlist, not upload-artifact glob behavior.
 local_files = ['package.zip', '.manifest', '.env']
 selected = [f for f in local_files if f in required]
 check('explicit allowlist includes reviewed manifest', '.manifest' in selected)
 check('explicit allowlist excludes credential fixture', '.env' not in selected)
 sequence = ['M1', 'M2', 'M3']
 check('M3 cannot skip M2', next_migration(sequence, ['M1'], 'M3') == 'prerequisite-missing')
 check('M2 eligible after M1', next_migration(sequence, ['M1'], 'M2') == 'eligible')
 check('M3 eligible after M2', next_migration(sequence, ['M1', 'M2'], 'M3') == 'eligible')
 check('unexpected ledger requires reconciliation', next_migration(sequence, ['M2'], 'M3') == 'reconcile')
 check('complete ledger avoids duplicate application', next_migration(sequence, sequence, 'M3') == 'already-complete')
 return dict(passed=len(checks), checks=checks, execution='local-synthetic-model', network=False, filesystemWrites=False,
 limitations=['No Azure pipeline or GitHub Actions run executed.', 'No YAML parser, scheduler, permission evaluation, action upload or database migration executed.', 'Models selected rules and fictional acceptance records; passing checks are not cloud-platform validation.'])


if __name__ == '__main__':
 print(json.dumps(run, indent=2))
IN PRACTICE

A reused agent publishes yesterday’s ZIP after a second checkout changes paths; the team must demonstrate F8/T3 and the required rehearsal before delivery.

Common pitfalls

Assuming upload success proves the candidate, completed means success or a queue automatically preserves every migration.

Related topics: Artifact identity and approvals · Repositories and reproducible builds · Migrations and recovery after failure

Take this idea with you

Before accepting delivery, connect inputs, attempt, output and approval. Reconcile external effects and canceled operations against actual prerequisites.

Create account

Reference: Check out multiple repositories · AZ-400 objectives 2026-07-27

Microsoft is a trademark of the Microsoft group of companies. bigsavant.com is an independent preparation platform and is not affiliated with, associated with, sponsored, authorised or endorsed by Microsoft. Content and questions are original, are not official exam questions, and completing our tests does not award or guarantee any certification. Names are used only to identify the subject. All other trademarks belong to their respective owners.