6.5.8 Complete CI Results with BEP/BES

A green CI tile is trustworthy only when it accounts for all intended work and all evidence needed to interpret that work. Bazel's Build Event Protocol (BEP) supplies structured invocation and test events, while the Build Event Service (BES) transports those events to a backend. Neither one knows whether your distributed CI plan was complete. Your result collector must join the event evidence to the partition manifest and refuse to turn a gap into a pass.

A green command is only one input to a complete CI result.
The collector joins intended work, event evidence, and required bytes before it chooses a lane verdict.

A four-step flow shows an immutable manifest, Bazel invocation events, a Build Event Service transport and event graph check, and required artifact retrieval joining in a collector. The collector returns complete only when every check agrees; explicit failures remain failed and missing or conflicting evidence remains unknown-delivery.

Question: The dashboard is green. Did every selected unit run, deliver coherent evidence, and leave every required artifact available?
1 · Intended work
Immutable partition manifest
revision, units, configuration, retries
2 · Invocation
Bazel emits results
targets, shards, runs, attempts
3 · Event evidence
BEP graph arrives
terminal state, announcements, duplicates
4 · Required bytes
Artifacts resolve
authorized, available, retained
RESULT COLLECTOR — THE JOIN POINT

Match every event and artifact to the same manifest, revision, configuration, and lane. A color in one system cannot fill a gap in another.

Complete
Every required predicate holds
eligible to report success or failure
Failed
Complete evidence of failure or abort
not a pass and not missing data
Unknown delivery
A required fact is absent or conflicts
missing partition, event, or bytes
Do not infer complete. A successful BuildFinished proves one command. The manifest, BEP graph, and artifact checks prove the CI lane.

Start from an Intended-Work Ledger

6.5.7 CI Work Distribution ends with a partition manifest: the jobs, labels, configurations, test shards, runs, and retry policy that CI intended to execute. Preserve that manifest under an immutable revision and configuration identity. It is the left side of the completeness comparison; events received from Bazel are the right side.

For each unit of intended work, record an identity precise enough to distinguish:

  • the source revision and CI lane;
  • the partition and Bazel invocation;
  • the target and configuration;
  • for tests, the shard, run, and attempt;
  • the terminal result and the artifacts required by your consumer.

The dimensions matter because BEP emits a TestResult for every test attempt, shard, and run. Its TestSummary aggregates a test's results and includes attempt, shard, and run counts so a consumer can distinguish flaky from failed outcomes.1 A collector keyed only by label can overwrite an earlier failure with the latest retry or collapse several shards into one apparent success.

A compact reconciliation record might look like this:

revision: <immutable-revision>
partition: linux-tests-03
invocation: <invocation-id>
unit: //search:index_test [configuration=<id>, shard=2, run=1]
attempts:
  - attempt=1, status=FAILED, artifacts=available
  - attempt=2, status=PASSED, artifacts=available
verdict: flaky

This is a design sketch, not a Bazel schema. Its important property is append-only attempt evidence. Policy may present the final verdict as flaky, failed, or passed, but it must not erase the history that produced that verdict.

Treat BEP as a Graph, Not a Log Tail

5.5.1 Build Event Protocol (BEP) introduces the event types for one invocation. At CI scale, completeness depends on their graph semantics. Every BEP event except the first is announced by an earlier event. When an invocation completes normally, every announced event is eventually posted; after a Bazel crash or failed transport, announced events can remain missing.2 A collector can therefore detect a protocol hole by retaining announced event identifiers and checking that each was fulfilled.

Do not equate seeing BuildFinished with consuming the last useful event. BuildFinished carries the command's authoritative exit code, but summary events such as metrics or profiling data may follow it.3 Nor does a successful BuildFinished prove that every CI partition was launched. It establishes the outcome of one Bazel command, not the coverage of the distributed plan.

Classify each invocation independently before rolling it into a lane verdict:

Invocation evidenceCollector state
terminal result, no unresolved announced events, expected work representedcomplete success or complete failure
explicit Aborted payload for work that did not complete normallycomplete evidence of an aborted result, not a pass
stream or file ends with unresolved announcements or without required terminal evidenceincomplete
duplicate delivery agrees with retained event identity and payloadduplicate, retained or deduplicated without changing outcome
duplicate identity carries conflicting evidenceconflicting and unsafe

An Aborted payload replaces the normal payload under an announced event identifier and explains why that event was not produced normally.4 Preserve it as terminal negative evidence for that event. Absence is different: it means the collector cannot establish what happened.

Delivery order must not become hidden correctness logic. BEP's parent-child relationship does not require every parent to be posted before its child, while referenced NamedSetOfFiles events have their own ordering rule: they appear before a TargetComplete or another named set that references them.5 Index events by identity, tolerate valid ordering and duplicate delivery, then evaluate the graph when sufficient evidence is available. “The most recent message wins” is not a reconciliation algorithm.

Separate Event Generation from Event Transport

Bazel generates BEP events. It can serialize them to a local binary, text, or JSON file, or publish them through its BES client. BES is a generic gRPC publishing protocol, independent of BEP, and transports BEP events as opaque bytes.6 A backend may add indexing, dashboards, retention, or consumer-specific completion state, but those are backend contracts rather than portable BEP semantics.

This gives an investigation three distinct checkpoints:

  1. Generation: Did the Bazel invocation produce the expected event graph?
  2. Transport: Did the configured file or BES path deliver that graph to the collector?
  3. Consumption: Did the backend reconcile it against the correct immutable work ledger?

6.1.4 Action and Result Lifecycle makes the same separation for remote action execution and result publication. A successful test action can still be followed by a failed event upload, and a complete event upload can still be attached to the wrong revision or partition manifest. Keep those failures attributable instead of reporting all of them as “test missing.”

Test the transport boundary deliberately. Cover a normal success, a build failure, client interruption, upload failure, reordered and duplicate delivery, and a conflicting duplicate. The expected outcome is not that every case produces a complete stream. It is that only the normal complete case can satisfy the success predicate, while failures remain failed or unknown rather than becoming green.

The runnable BEP complete-result fixture captures real local BEP JSON streams for both a passing and an intentionally failing Bazel test, then checks each against an immutable partition, shard, run, and attempt manifest plus the actual test log. It uses the failing stream as a control: complete evidence of a failed test must be failed, not unknown-delivery. Deterministic collector-input mutations then remove terminal, result, summary, manifest-obligation, partition, shard, retry, or artifact evidence; replace an announced nonterminal event's normal payload with Aborted; and add a conflicting duplicate. Those mutations exercise the collector contract; they are not claimed to be a live BES deployment.

Events Can Be Complete While Artifacts Are Missing

BEP events commonly refer to files instead of embedding their bytes. TargetComplete points to one or more NamedSetOfFiles structures, which may recursively refer to other named sets. This sharing avoids repeatedly listing the same files, but a consumer must traverse the structure with a visited set and retain named sets until the stream is exhausted.5

Resolving the graph yields file metadata or a URI; it does not by itself prove that the bytes are available to the consumer. The official BES guidance calls out the boundary directly: test logs and XML files may exist only on the Bazel machine, which a remote BES server cannot access. Remote caching is one way to upload referenced outputs so that the BES server can fetch them.7

For every artifact required by your CI contract, track four separate facts:

  • its reference was present in the event graph;
  • the full named-set path was resolvable;
  • the authorized consumer could retrieve the bytes;
  • retention covers the period in which downstream consumers need them.

An authorization error is not proof that a blob is absent, and a resolvable URI is not proof that it exists. Report those states separately. Profiles, test logs, XML reports, coverage files, and build outputs may also have different retention and access rules; do not infer a shared lifecycle from their appearance in one event stream.

think

Decide: Every partition has a successful BuildFinished, every announced BEP event was received, and the dashboard can resolve all NamedSetOfFiles references. One required test log URI returns “not found.” May the lane be marked complete and green?

Reveal

Not if the lane contract requires that log. Event completeness and artifact availability are separate predicates. Record the invocation result as successful, the BEP delivery as complete, and the required artifact evidence as incomplete; the combined lane result remains unknown rather than green.

Define One Complete-Result Predicate

Make the gating condition explicit and machine-testable. For a revision and lane, a result is complete only when:

  1. the intended-work ledger has an immutable identity;
  2. every intended partition and invocation is accounted for;
  3. every intended target, configuration, shard, and run has the required attempt evidence;
  4. every invocation has a terminal success, failure, cancellation, or explicit incomplete state;
  5. no required announced BEP event is unresolved and no conflicting event remains;
  6. every required referenced artifact is resolvable, authorized, available, and retained under the lane's contract;
  7. all evidence names the same revision, universe, and policy versions.

The predicate should return at least complete, failed, and unknown-delivery, not a single Boolean. A test failure with complete evidence is different from missing evidence. Both block a green result, but only the former proves that the tested code failed.

Exercise the predicate with adversarial fixtures. Remove one partition record, one shard result, one retry attempt, one announced event, and one referenced artifact in turn. Add a cancellation and two conflicting events with the same identity. Each mutation must prevent a false green while preserving the evidence that explains why. Include a fully delivered failing invocation as a control: the system should report a complete failure, not confuse any non-green result with incomplete delivery.

The output is an immutable technical handoff: revision identity, intended-work ledger, invocation results, event-graph verdicts, and artifact-availability verdicts. H.7.5 Merge Queue decides when that handoff permits queue advancement, and H.7.4 Change Admission decides which lanes and scopes are required. The collector supplies trustworthy evidence; it does not advance workflow state itself.

key takeaway

A complete CI result is a reconciliation, not a dashboard color. Join the immutable partition manifest to configuration-aware target, shard, run, and attempt evidence; retain failures, retries, cancellations, conflicts, and missing events as distinct states. BuildFinished proves one command's outcome, while the BEP graph and intended-work ledger establish whether all promised work was observed.

Keep event delivery separate from artifact availability. Traverse every required NamedSetOfFiles reference, then prove that an authorized consumer can retrieve and retain the bytes. Only an explicit predicate covering intended work, terminal events, conflict-free delivery, and required artifacts may emit a complete result; every unresolved gap remains unknown and cannot become green.

Check your understanding · 4 questions

1.A lane's manifest declares Linux and Windows invocations for the same test label. Linux ends with a successful BuildFinished event, but no Windows invocation arrives. What should the collector report?

Select one answer

2.Decide whether each CI collector claim is true or false:

Choose True or False for each sentence

A successful BuildFinished event proves every CI partition in the lane ran.
An Aborted payload is explicit evidence that an announced event did not finish normally.
A duplicate event with the same identity and same payload can be retained or deduplicated without changing the verdict.

3.When a lane requires a test log, which facts must the collector establish before it can treat that artifact as available?

Select all that apply

4.Match each reconciled lane state to the collector outcome:

Drag each answer onto the matching prompt, or click an answer and then click a prompt

Answers
All declared work and required artifacts are present; the tests passed
All declared work is present; a test failed with terminal evidence
The stream ends while an announced required event is still missing
0 of 4 answered

Footnotes

  1. Build Event Protocol GlossaryTestResult and TestSummary identities across attempts, shards, and runs

  2. Build Event Protocol — event announcement guarantees and incomplete graphs after crashes or transport failures

  3. Build Event ProtocolBuildFinished placement and possible trailing summary events

  4. Build Event Protocol GlossaryAborted payload semantics

  5. Build Event Protocol ExamplesNamedSetOfFiles references, ordering, recursive traversal, and deduplication 1 2

  6. Build Event Protocol — separation between BEP event semantics and generic BES transport

  7. Build Event Protocol — remote BES access to referenced files through remote caching