Make it impossible for a flow to silently produce no result. A flow that aborts mid-run or is skipped before validation emits a distinct, structured placeholder row, and Grafana/Slack surface aborted/skipped distinctly from event-misses. The foundation Phase 5's dry-run gate depends on.
Not the matching change (Phases 5/6). Not capture changes (Phase 3). Not failureKind taxonomy (Phase 7, built on this phase's field). Strictly additive on the result contract.
outcome field.On both ReportDetailRow and ValidationResult: outcome: "validated" | "section-aborted" | "flow-skipped". Every existing field keeps its name, type, and meaning. The additive field Phase 7's failureKind will build on.
passed on aborted/skippedpassed: false — pre-existing dashboards still flag.outcome is the discriminator for why it failed (not run vs tracking missing). Old failure queries keep working.
Compute the planned flow set per domain from config; diff against emitted reportDetailRows; for every planned flow with no emitted row, push a flow-skipped placeholder.
Wrap each per-section dispatch in bi-measurement.ts in try/catch; on throw, push a section-aborted row carrying short error summary, continue to next section.
Single writer helper emitOutcomeRow() in eventUtils.ts; keeps the singleton drain/reset contract intact.
outcome facet, no renames.outcome becomes a queryable field in the OpenSearch/Grafana payload. New "⚠️ Aborted / Skipped flows" block in Slack, listed separately from event-miss.
section-aborted row carrying truncated error summary; run continues to the next section.flow-skipped row per planned flow with no emitted result.passed: false on aborted/skipped rows preserves existing failure-query behavior.