# Observability for Business Automations: Evidence Dossier

**Research snapshot:** October 10, 2026  
**Perspective:** General  
**Decision supported:** How can a team see that the expected result happened, rather than merely that an automation job ran?  
**Scope anchor:** A bounded synthetic daily data-delivery process: an expected source export arrives, is preserved, ingested and transformed in an analytical warehouse, and a downstream business report must become usable by a declared deadline.

## Decision answer

The strongest design is not “better job monitoring.” It is a **separate outcome-reconciliation loop keyed to expected business work**.

A scheduler saying `SUCCESS`, an HTTP endpoint returning an acceptance response, a notification being delivered, or a table containing some rows proves a technical event occurred. It does not, by itself, prove that the correct business batch arrived, was completely processed, produced valid data, and made the current report available by the promised deadline. OpenLineage, for example, defines `COMPLETE` specifically as the conclusion of job execution; dbt separately implements source-freshness checks and data assertions; Google SRE distinguishes internal white-box telemetry from black-box checks of externally visible behavior. Together these sources support the distinction between **execution evidence and outcome evidence**. citeturn21view6turn21view4turn21view5turn21view0

The recommended minimal design is:

> **Expected work → independent reconciliation → persistent case → actionable notification → repair → re-reconciliation → verified closure**

For the daily report, create a durable expected-work record *before or independently of the main workflow*, such as:

`daily_sales:2026-10-09:Europe/Prague`

That case defines what “done” means: the expected source period, deadlines, owner, required preservation evidence, warehouse batch identity, business invariants, and downstream report state. A reconciler then checks those conditions directly. The business case is only successfully delivered when its outcome evidence passes. This is an architectural recommendation synthesized from the evidence rather than a feature prescribed by any one cited platform.

A useful formal distinction is:

\[
\text{DeliveredOnTime}(c)=
S_c \land P_c \land B_c \land I_c \land R_c \land (t_{report}\leq D_c)
\]

where:

- \(S_c\): expected source for case \(c\) is present,
- \(P_c\): recoverable raw input is preserved,
- \(B_c\): warehouse output represents the correct business batch,
- \(I_c\): declared business invariants pass,
- \(R_c\): the downstream report represents the correct period and is actually available,
- \(D_c\): declared business deadline.

A late repair should **not rewrite history**. Instead:

\[
\text{Recovered}(c,t)=
S_c \land P_c \land B_c \land I_c \land R_c
\]

at verification time \(t>D_c\), while `DeliveredOnTime(c)` remains false. That prevents an eventual successful rerun from erasing a missed service commitment.

### What should remain as an alert?

The draft claim *“Automation sends so many notifications that nobody reads them. Which should remain?”* is directionally defensible but should be qualified rather than presented as a universal empirical law. Google SRE explicitly warns that overly frequent paging leads responders to second-guess, skim or ignore pages and can allow an important page to be masked by noise; its design guidance asks whether an alert is urgent, actionable and user-visible. Prometheus similarly treats grouping as a way to produce one compact notification **while retaining exactly which instances are affected**. A 2024 peer-reviewed cloud-monitoring study tested ML filtering on two datasets supplied by Netdata and reports greater than 90% classification accuracy in most tested cases, but that result does **not** establish that aggressively suppressing alerts improves business outcomes across organizations. citeturn7view0turn21view1turn21view2turn19view3

The better rule is:

> **Reduce notifications, not cases.**

Every distinct affected business batch should retain its own identity and resolution state. Several cases may be grouped into one notification to reduce interruption. They should not be collapsed into one indistinguishable incident merely because the symptom or alert name is the same. Prometheus explicitly supports grouping many alerts into one notification while retaining the individual affected instances; PagerDuty documents that events sharing a `dedup_key` are applied to the same open alert, illustrating why the choice of deduplication key changes case semantics. citeturn21view2turn16view2

### Main uncertainties

The strongest public evidence here consists primarily of mature operational guidance, protocol/platform semantics and data-engineering design documentation, rather than randomized studies comparing “job monitoring” against “business-outcome reconciliation.” Google’s SRE material is attributable large-scale operational practice, but it is not controlled causal evidence. Provider documentation proves feature behavior, not that adopting that feature improves a business KPI. citeturn21view0turn17view3turn17view4

There is empirical evidence that alert overload can be mitigated by classification approaches in cloud monitoring, but evidence for **AI triage in business-data automation specifically** is weak. A May 2026 systematic survey of AI alert screening found only 9 of its 87 core studies in its production/field evidence tier and identified persistent gaps in operational validation and cross-environment generalization; its domain is security operations, so transfer to analytical data operations should be treated as an analogy, not direct evidence. citeturn19view2turn20view0

## Anchored process and baseline

### Recognizable process

The evidence dossier uses this synthetic process throughout:

| Element | Defined process |
|---|---|
| Business process | Daily sales-data delivery |
| Trigger | A source system is expected to export one completed business-day batch |
| Business identity | `process + business_date + scope + timezone` |
| Example identity | `sales_daily:2026-10-09:Europe/Prague` |
| Inputs | Expected-work/calendar record, source file/export, raw preserved copy, warehouse tables, transformation results, report metadata/content |
| Primary owner | Data/report product owner owns the meaning of successful delivery |
| Operational owner | Analytics/data on-call owns an open delivery case until handoff or verified closure |
| States | Expected → source present → preserved → ingested → validated → report ready → verified |
| Exception states | Missing, late, stale, partial, invalid, recovering, verified late |
| Successful observable outcome | Report contains the intended business period, declared invariants pass, and report is accessible by the declared deadline |
| Recovery evidence | Reconciliation for the **same case identity** passes after repair; lateness remains recorded |

The exact thresholds in this dossier are synthetic, not measured production requirements.

### Why batch identity matters

“Today’s data” is ambiguous unless the business period and the time at which processing occurred are distinguished. Apache Flink's documentation explicitly separates **event time**, the time associated with the original event, from **processing time**, the system time when computation runs; it also explains that out-of-order or delayed processing can make these diverge. The same distinction applies to batch reporting even when Flink is not used: a report generated on October 10 may legitimately represent October 9, and the report's creation timestamp alone cannot establish its business freshness. citeturn18view2turn18view3

For a daily workflow, therefore, preserve at least:

```text
case_id
business_date
business_timezone
expected_source_deadline
expected_report_deadline
observed_source_business_date
observed_report_business_date
processing timestamps
```

Timezone handling should use named IANA zones rather than permanently hard-coded UTC offsets. IANA states that its Time Zone Database is periodically updated when political bodies change UTC offsets, boundaries or daylight-saving rules; the latest version at this research snapshot was **2026e, released September 29, 2026**. citeturn17view0

### Simplest manual/native baseline

Before buying an observability platform, the simplest credible baseline is a **daily reconciliation checklist**.

At, for example, 08:05 Europe/Prague, a named owner opens an expected-work sheet containing one row per business date and checks:

| Check | Evidence recorded |
|---|---|
| Was a delivery expected today? | Expected-work row and business calendar |
| Did the correct source export arrive? | File/object identifier plus source business date |
| Was the raw input preserved? | Immutable/recoverable location and optionally checksum |
| Did the correct batch reach the warehouse? | Query result keyed to business date/batch ID |
| Did declared invariants pass? | Stored query/test result |
| Does the report expose the intended period? | Report `as_of`/period field |
| Is the report actually accessible? | Black-box access check or verified report URL/state |
| Was it ready by the deadline? | Observed availability timestamp versus declared deadline |
| If not, who owns the case? | Named person/team plus escalation time |
| After repair, did the same checks pass? | New reconciliation timestamp and evidence |

This is a **synthetic recommended baseline**, not a claim that spreadsheets are inherently reliable. In fact, Google SRE argues that well-scoped known procedures gain consistency from automation because humans do not perform repeated actions identically. The value of doing this manually first is different: it exposes ambiguities in the process and forces the team to define what should eventually be automated. Google also cautions that automation is a force multiplier rather than a panacea and that thoughtless automation can create problems as readily as solve them. citeturn16view0

### Clarify before automating

For this process, I would not automate an ambiguous statement such as:

> “Refresh sales report every morning.”

I would first standardize it into:

> “For every Czech business date for which an export is expected, the report for that exact business date must be accessible by 08:00 Europe/Prague, use the preserved source batch for that date, and pass invariants X, Y and Z.”

Then automate the evidence collection and reconciliation.

This is important because a scheduler cannot infer an omitted business contract. Automating an unclear step gives you consistently unclear behavior with better uptime.

## Evidence synthesis and design choices

### Job telemetry is useful but not sufficient

Execution telemetry should stay. It answers valuable questions: Did the process start? Which task failed? How long did it take? Which datasets participated? OpenLineage, for example, represents job/run/input/output relationships and reports lifecycle states including `START`, `RUNNING`, `COMPLETE`, `FAIL` and `ABORT`, making it suitable for correlating execution across stages. citeturn21view6

The limitation is semantic. OpenLineage defines `COMPLETE` as meaning that execution concluded, not that a downstream business user received the intended current-period result. That latter conclusion requires an additional business assertion. citeturn21view6

Google's SRE experience with periodic pipelines also documents lifecycle failures that a happy-path “job finished” view does not solve: pipeline performance can degrade with growth, jobs can miss deadlines or hang, and standard monitoring patterns may report metrics only when a job completes, leaving no statistics when execution itself fails. citeturn17view3

### Source freshness and business correctness are different checks

dbt provides an unusually clear illustration. Its documentation states that `dbt build` does **not** automatically include source-freshness checks. Source freshness must be explicitly configured; whether freshness failure blocks later job steps depends on how it is configured. citeturn21view4

Separately, dbt data tests are assertions over resulting data. Built-in tests cover properties such as non-nullness, uniqueness and referential relationships, while arbitrary SQL assertions can represent organization-specific business logic; a test passes when the query returns zero failing rows. citeturn21view5

So at least three questions exist:

\[
\text{Did code execute?}
\neq
\text{Is the input fresh?}
\neq
\text{Is the result correct?}
\]

And the present decision adds a fourth:

\[
\text{Is the intended business output actually available?}
\]

A robust automation explicitly answers all four where they matter.

### Expected work must exist even when no run exists

This is the most important architectural move.

Consider a scheduler that never creates today's run because its scheduler process, permission, trigger or upstream event failed. Monitoring only the resulting runs asks:

> “Which runs failed?”

But there may be no run to inspect.

The independent question is:

> “Which business deliveries were expected by now, and which lack verified completion?”

Airflow 3.3.2 provides deadline alerts for DAG runs and supports both built-in and custom deadline references, but its documented mechanism is centered around DAG-run deadline evaluation. The feature is also explicitly marked experimental as of version 3.3.2. citeturn21view3

**Interpretation:** Airflow deadlines are useful workflow telemetry, but they should not automatically be treated as an independent proof that every expected business occurrence existed. If the failure mode of concern can prevent the relevant workflow/run from being represented at all, the expectation should live in a failure domain capable of detecting that absence.

A minimal expected-work table is enough:

```sql
create table expected_delivery (
    case_id                 varchar primary key,
    process_name            varchar not null,
    business_date           date not null,
    business_timezone       varchar not null,
    source_deadline_utc     timestamp with time zone,
    report_deadline_utc     timestamp with time zone not null,
    owner                   varchar not null,
    expectation_version     varchar not null,
    expected                boolean not null default true
);
```

How those rows are generated can remain simple: a business calendar table plus a tiny independent scheduled query may be sufficient. A dedicated observability product is not a prerequisite.

### Minimal sufficient architecture

The smallest architecture I would recommend is:

```text
                         ┌─────────────────────┐
                         │ Expected-work table │
                         │ case/date/deadline  │
                         └──────────┬──────────┘
                                    │
                                    v
Source → raw copy → warehouse → report
   │         │          │          │
   └─────────┴──────────┴──────────┤
                                   v
                           ┌───────────────┐
                           │ Reconciler    │
                           │ direct checks │
                           └───────┬───────┘
                                   │
                      pass         │        fail/late
                    ┌──────────────┴──────────────┐
                    v                             v
             outcome evidence              persistent case
                                                  │
                                                  v
                                             alert route
                                                  │
                                                  v
                                               owner
                                                  │
                                               repair
                                                  │
                                                  v
                                            reconciler
                                                  │
                                                  v
                                          VERIFIED/CLOSED
```

Lineage can enrich the middle by correlating relevant runs and datasets, but it should not be the definition of expected work. OpenLineage is valuable for correlating job, run, input and output metadata; it does not by itself provide the business calendar that says a report *should have existed today*. citeturn21view6

### Design alternatives

| Approach | What it proves | Silent missing-run detection | Wrong-result detection | Upkeep | Assessment |
|---|---|---:|---:|---|---|
| Scheduler success/failure only | Workflow execution state | Weak | Weak | Low | Insufficient alone |
| Manual reconciliation checklist | Whatever humans explicitly check | Yes | Potentially strong | Human effort | Best discovery/baseline |
| Scheduler + native freshness/tests | Run + selected data properties | Conditional | Moderate/strong for encoded tests | Low–moderate | Good low-cost step |
| Independent expected-work reconciler | Expected occurrence + business state | Strong | Strong if invariants are well specified | Moderate | **Recommended core** |
| Full observability/lineage platform | Cross-system telemetry and correlations | Depends on configuration | Depends on assertions | Moderate–high | Add when complexity warrants |
| AI triage/incident agent | Context, summaries, likely correlations | Should not be source of truth | Should not be closure authority by default | Model + prompt + evaluation upkeep | Bounded adjunct |

The relative assessment in this table is a reasoned architectural comparison, not measured comparative performance.

### Recovery is a feature, not a footnote

Google's data-integrity guidance is particularly relevant here: it argues for focusing on recoverability rather than merely possessing backups, recommends measurable tests of recovery capability, and reports an internal study of 19 Google data-recovery efforts in which especially difficult cases involved low-grade corruption or deletion discovered weeks or months after introduction. The sample is small and Google-specific, so it should not be generalized into an industry frequency estimate, but it is useful evidence that delayed, subtle wrong-state failures deserve explicit recovery design. citeturn17view4

For this daily delivery, preserving raw source input is therefore more valuable when paired with a tested question:

> Can we reconstruct batch `2026-10-09`, validate it, republish its report and prove that the corrected batch—not a different one—is now serving?

Google likewise cautions that replication is not equivalent to recoverability because corruption or erroneous deletion may replicate to every serving copy. citeturn17view4

## Actionable alerts, failure and recovery

### Alert-to-action inventory

The central editorial recommendation is not “fewer alerts at any cost.” It is **fewer interruptions, with every unresolved business case still represented**. Google SRE recommends alerts that are urgent and actionable; Prometheus Alertmanager explicitly separates grouping, inhibition and silencing as mechanisms for controlling notifications. citeturn21view1turn21view2

A reusable inventory for the anchored process:

| Condition | Detector | Case key | Owner | Notification | First action | Evidence required for closure |
|---|---|---|---|---|---|---|
| Expected source absent after deadline | Expected-work reconciler, not source event | `process:business_date:scope` | Source/data owner | Page if report deadline endangered; otherwise ticket | Confirm whether source was legitimately cancelled | Correct source identified or expectation explicitly cancelled with audit reason |
| Source arrived with wrong period | Source metadata/content reconciliation | Same business case | Data on-call | Actionable alert | Quarantine; locate correct batch | Correct business-period source preserved |
| Raw recovery copy missing | Preservation check | Same business case | Platform/data owner | Ticket unless immediate recovery risk is material | Restore preservation path | Recoverable raw copy independently visible |
| Warehouse batch missing/partial | Deterministic reconciliation | Same business case | Pipeline owner | Page/ticket based on deadline | Compare source versus loaded scope | Correct period and completeness checks pass |
| Business invariant fails | SQL/data-test layer | Same business case | Data product owner | Usually actionable | Inspect failing records and recent changes | Zero unexpected failing records or formally approved rule change |
| Report exists but is stale | Black-box/report metadata check | Same business case | Report owner | Page near/after business deadline | Check serving/cache/report refresh | Report states correct business period and is retrievable |
| Report correct but late | Deadline comparison | Same business case | Data service owner | Incident/ticket depending on impact | Restore delivery | Current result verified; SLO miss retained historically |
| Main reconciler has stopped checking | Independent heartbeat/age check | `monitor:<reconciler>` | Platform owner | Secondary route | Restore checker | Checker executes and reconciles backlog |
| Alert route not confirmed | Notification-path watchdog | `notification-route:<route>` | Operations owner | **Different route** | Validate receiver/escalation configuration | Test receipt through intended route |
| Case acknowledged but not fixed | Case-age/escalation rule | Original business case | Current assignee → escalation owner | Escalate | Continue recovery | Outcome re-reconciliation passes |

This table is a **recommended design asset**, not a claim that every organization needs every row.

### Receipt, acknowledgement and resolution are different states

PagerDuty's documented incident lifecycle is useful because it explicitly distinguishes them: a triggered incident requires attention; **acknowledged** means someone is working on it but it is not yet resolved; **resolved** means the problem has been fixed. PagerDuty also documents that a coverage gap with nobody on call can result in no incident being created for an incoming event, which is a concrete example of why the alerting system itself belongs inside the reliability model. citeturn18view0turn18view1

For business automation I would use an even stricter state machine:

```text
OPEN
  ↓
ACKNOWLEDGED       # human owns it; nothing proven about business result
  ↓
RECOVERING         # corrective work underway
  ↓
RECHECKING         # deterministic outcome checks running
  ↓
VERIFIED           # expected current state proved
  ↓
CLOSED             # administrative closure
```

A message receipt is not acknowledgement.  
Acknowledgement is not repair.  
Repair execution is not verification.  
Verification is not retroactive on-time delivery.

### Resolution-evidence matrix

| Evidence | Alert sent? | Human engaged? | Problem repaired? | Business outcome proved? | Close case? |
|---|---:|---:|---:|---:|---:|
| Notification API/route accepted message | Yes | No | No | No | No |
| Human acknowledges | Yes | Yes | No | No | No |
| Rerun returns green | Yes | Usually | Maybe | No | No |
| Table now contains rows | Yes | Usually | Maybe | No | No |
| Correct business period present | Yes | Usually | Partly | Partly | No |
| Business invariants pass | Yes | Usually | Likely | Partly | No |
| Correct downstream report independently observed | Yes | Usually | Yes | Yes, current state | Potentially |
| Above plus timestamp ≤ original deadline | Yes | Usually | Yes | Yes, on time | Yes: delivered |
| Above but timestamp > original deadline | Yes | Usually | Yes | Yes, late | Yes: recovered late; preserve miss |

The underlying reasoning is consistent with Google SRE's preference for monitoring user-visible symptoms rather than merely causes, and with dbt's distinction between execution, source freshness and data assertions. citeturn21view0turn21view4turn21view5

### Worked synthetic failure: deduplication hides a second batch

**This is a reasoned synthetic scenario, not a reported customer incident.**

Two business cases are open:

```text
sales_daily:2026-10-08:Europe/Prague
sales_daily:2026-10-09:Europe/Prague
```

The first has a technically completed pipeline but the report still says `as_of=2026-10-07`.

The second produces the correct report period, but only 60 rows reach the warehouse against a synthetic floor of 100 and three rows violate a declared transformation invariant.

A naive alerting system emits both as:

```text
alert_name = "daily_sales_report_problem"
dedup_key  = "daily_sales_report_problem"
```

PagerDuty documents that subsequent events using a matching `dedup_key` are applied to the same open alert; Prometheus also supports alert grouping, although its documented grouping model deliberately retains visibility of individual affected instances. citeturn16view2turn21view2

The dangerous implementation mistake is therefore not grouping itself. It is **discarding the affected case identities**.

Use:

```text
case_key = sales_daily:2026-10-08:Europe/Prague
case_key = sales_daily:2026-10-09:Europe/Prague

notification_group = sales_daily_delivery
affected_cases = [
  sales_daily:2026-10-08:Europe/Prague,
  sales_daily:2026-10-09:Europe/Prague
]
```

One page can represent both cases. Each case must still retain independent state.

Suppose the first report is repaired. Its deterministic reconciliation becomes green, so:

```text
2026-10-08 → VERIFIED_LATE/CLOSED
2026-10-09 → OPEN
```

If the notification group rather than the business case were the unit of resolution, fixing the first problem could wrongly make the second disappear operationally.

Now add a second failure: the alert transport does not confirm delivery. The business cases must remain open in the durable case ledger regardless; a notification watchdog opens a separate `ALERT_TRANSPORT_UNCONFIRMED` case via another route. This particular watchdog design is a proposed architecture pattern, not documented PagerDuty or Prometheus behavior.

### Noise without information loss

The practical distinction is:

\[
\text{Deduplicate repeated evidence for the same case}
\]

versus

\[
\text{Do not deduplicate distinct affected business cases into nonexistence}
\]

Good grouping:

```text
1 page
 ├── batch 2026-10-08 — stale report
 └── batch 2026-10-09 — partial transform
```

Bad grouping:

```text
1 incident: "daily report broken"
status: RESOLVED
```

where nobody can tell whether both batches recovered.

Prometheus's documentation gives direct support to the underlying pattern: group many alerts so the responder gets a single compact notification **while still being able to see exactly which instances were affected**. citeturn21view2

### AI triage: useful boundary, weak basis for autonomous closure

There is a credible role for AI after a deterministic case exists:

```text
deterministic detector
        ↓
persistent case
        ↓
AI enrichment:
- summarize evidence
- correlate lineage/runs
- retrieve relevant runbook
- rank plausible causes
- draft investigation steps
        ↓
human decision / bounded approved action
        ↓
deterministic reconciliation
        ↓
verified closure
```

The case should not disappear because an LLM concludes it is probably benign.

The evidence warrants caution. A 2026 systematic survey covering 119 records, including 87 core studies, found that algorithmic progress in security-alert screening had outpaced operational validation; only nine core studies fell into its production/field tier, and it specifically identifies cross-environment generalization, operational validation and governance as gaps. The authors frame human decision authority as important for high-stakes actions. This is security-operations evidence rather than data-pipeline evidence, so it supports a **cautious analogy**, not a proven effect in business automation. citeturn19view2turn20view0

The 2024 Voutsas et al. study is more directly about cloud-monitoring alerts. It tested a composite ML filtering method using two Netdata-provided datasets and had company engineers evaluate results, reporting greater than 90% accuracy in most cases. That demonstrates feasibility in that setting, but neither classification accuracy nor expert validation proves that autonomous suppression would preserve every important business-data case. citeturn19view3

My recommendation is therefore **AI for compression and investigation leverage; deterministic rules for expectation creation and resolution truth**.

## Claim-to-source dossier

The table separates provider behavior, reported practice, empirical evidence and this dossier's interpretation. “Supported” means the cited source directly supports the scoped statement—not that it establishes universal causal effectiveness.

| Claim / decision use | Primary source and exact section | Source date | Inspected | Evidence type | Status | Editorial advice |
|---|---|---|---|---|---|---|
| Internal job telemetry and externally visible outcome monitoring are different | Google SRE, *Monitoring Distributed Systems*, “Definitions”: white-box vs black-box monitoring | 2016 book | 2026-10-10 | Attributable practitioner design guidance | **Supported** | **Keep.** Describe black-box check as outcome-facing evidence, not complete proof by itself. URL: https://sre.google/sre-book/monitoring-distributed-systems/ citeturn21view0 |
| Excessive paging can make important signals less effective; alerts should be actionable | Google SRE, “As Simple as Possible, No Simpler” / alert-design questions; earlier discussion of paging noise | 2016 book | 2026-10-10 | Reported operational practice/design guidance | **Supported directionally** | **Qualify.** Do not turn “can lead to ignoring” into “everyone ignores alerts.” URL: https://sre.google/sre-book/monitoring-distributed-systems/ citeturn21view1turn7view0 |
| Automation helps consistency but can amplify a bad design | Google SRE, *The Evolution of Automation at Google*, opening and “Consistency” | 2016 book | 2026-10-10 | Attributable practitioner design guidance | **Supported** | **Keep.** Useful rationale for clarifying the process before automating it. URL: https://sre.google/sre-book/automation-at-google/ citeturn16view0 |
| Periodic pipelines develop deadline/hanging/monitoring failure modes over their lifecycle | Google SRE, *Data Processing Pipelines*, “Challenges with the Periodic Pipeline Pattern” and “Monitoring Problems” | 2016 book | 2026-10-10 | Reported Google operational experience | **Supported in Google scope** | **Keep, qualify scope.** Not an industry failure-rate estimate. URL: https://sre.google/sre-book/data-processing-pipelines/ citeturn17view3 |
| Job `COMPLETE` is an execution lifecycle state, not an explicit business-result guarantee | OpenLineage, *The Run Cycle*, “Run States” | v1.53.0; page date not exposed | 2026-10-10 | Specification/provider documentation | **Documented behavior + interpretation** | **Keep with wording.** Say `COMPLETE` means execution concluded; the insufficiency for business outcome is the dossier's inference. URL: https://openlineage.io/docs/spec/run-cycle/ citeturn21view6 |
| Source freshness is not automatically equivalent to a successful dbt build | dbt, *Source freshness*, “Enabling source freshness checks” | Updated 2026-10-06 | 2026-10-10 | Provider documentation | **Supported, dbt-specific** | **Keep.** Excellent concrete example of separate success dimensions. URL: https://docs.getdbt.com/docs/deploy/source-freshness citeturn21view4turn18view5 |
| Business assertions can be encoded as deterministic data tests | dbt, *Add data tests to your DAG*, “Overview” | Updated 2026-09-16 | 2026-10-10 | Provider documentation | **Supported, dbt-specific** | **Keep.** Do not imply built-in tests know an organization's business meaning automatically. URL: https://docs.getdbt.com/docs/build/data-tests citeturn21view5turn18view4 |
| Workflow deadline features do not remove the need to reason about absent expected work | Apache Airflow, *Deadline Alerts*, introduction / reference model | Airflow 3.3.2; feature introduced in 3.1 and marked experimental | 2026-10-10 | Provider documentation + architectural inference | **Conditional** | **Qualify strongly.** Docs establish DAG-run deadline behavior; independence from a missing run is an inference. URL: https://airflow.apache.org/docs/apache-airflow/stable/howto/deadline-alerts.html citeturn21view3 |
| Notification grouping can reduce interruption while preserving individual affected entities | Prometheus, *Alertmanager*, “Grouping” | Live docs; exact publication date not exposed | 2026-10-10 | Provider documentation | **Supported** | **Keep.** Generalize as a design pattern, not proof that a specific group key is correct. URL: https://prometheus.io/docs/alerting/latest/alertmanager/ citeturn21view2 |
| A broad dedup key changes which incoming events share one open alert | PagerDuty, *Sending an Alert Event*, “Alert De-Duplication” | Live 2026 developer docs; exact update date not exposed | 2026-10-10 | Provider documentation | **Supported, PagerDuty-specific** | **Keep as worked example.** The proposition that batch ID belongs in the business-case key is this dossier's design recommendation. URL: https://docs.pagerduty.com/developer/send-alert-event citeturn16view2 |
| Acknowledged and resolved are distinct incident states; alerting configuration can itself have silent gaps | PagerDuty, *Incidents*, “Incident Lifecycle” | Live 2026 docs; exact update date not exposed | 2026-10-10 | Provider documentation | **Supported, PagerDuty-specific** | **Keep.** Then add stricter outcome verification at the application layer. URL: https://support.pagerduty.com/main/docs/incidents citeturn18view0turn18view1 |
| Event/business time should not be conflated with processing time | Apache Flink, *Timely Stream Processing*, “Notions of Time: Event Time and Processing Time” | Stable documentation; page date not exposed | 2026-10-10 | Provider/project documentation | **Supported** | **Keep.** Transfer conceptual distinction to batch business dates explicitly as interpretation. URL: https://nightlies.apache.org/flink/flink-docs-stable/docs/concepts/time/ citeturn18view2turn18view3 |
| Local civil-time rules can change; software needs updated zone rules | IANA, *Time Zones* | tzdb 2026e released 2026-09-29 | 2026-10-10 | Primary standards/infrastructure source | **Supported** | **Keep.** Use to justify IANA zone identifiers and calendar-aware deadlines. URL: https://www.iana.org/time-zones citeturn17view0 |
| Recovery capability is more meaningful than merely claiming a backup exists | Google SRE, *Data Integrity*, “Delivering a Recovery System, Rather Than a Backup System”; “Types of Failures” | 2016 book | 2026-10-10 | Operational guidance plus internal study of 19 recovery efforts | **Supported in scoped evidence** | **Keep; qualify 19-case study.** Do not derive an industry prevalence estimate. URL: https://sre.google/sre-book/data-integrity/ citeturn17view4 |
| ML can filter monitoring alerts successfully in a specific cloud-monitoring dataset/setting | Voutsas, Violos & Leivadeas, *Computer Networks* 250, article 110543 | Aug. 2024 | 2026-10-10 | Peer-reviewed empirical study; two Netdata datasets and expert evaluation | **Supported in study scope** | **Qualify heavily.** Accuracy is not evidence of business-outcome reliability or safe autonomous closure. DOI: https://doi.org/10.1016/j.comnet.2024.110543 citeturn19view3 |
| AI alert triage still lacks broad operational/generalization evidence | Ndichu et al., *AI-Driven Security Alert Screening...*, abstract, evidence-tier analysis, limitations | arXiv v2, 2026-05-18; submitted manuscript | 2026-10-10 | Systematic survey preprint, SOC/security scope | **Supported in SOC literature; indirect here** | **Keep as caution, not direct data-ops evidence.** URL: https://arxiv.org/html/2605.08316v2 citeturn19view2turn20view0 |

### Draft-claim disposition

For the Czech draft target:

> **“Automatizace posílá tolik upozornění, že je nikdo nečte. Která mají zůstat?”**

I would **rewrite**, not remove:

> **“Když automatizace hlásí každý technický výkyv, důležitý problém může zapadnout. Upozornění má zůstat hlavně tehdy, když vyžaduje konkrétní reakci; související případy lze seskupit, ale jednotlivé nevyřešené business případy se nesmějí ztratit.”**

Evidence status: **supported directionally** by Google SRE's reported operational practice and by documented grouping mechanisms, with empirical but setting-specific support that alert filtering is feasible. It is **not** supported as a universal causal statement that a particular alert volume inevitably causes all teams to stop reading notifications. citeturn7view0turn21view1turn21view2turn19view3

## Limitations, contradictions, and context

### Where the recommendation can fail

**Independent reconciliation adds another production system.** The proposed checker can itself stop running, lose permissions, or read stale metadata. That is why it needs a last-success/heartbeat check from a different failure domain. This moves rather than eliminates the classic “who monitors the monitor?” problem. The gain is not perfect reliability; it is making expected absence explicit and independently testable.

**Independence is relative.** A second DAG in the same broken scheduler is not meaningfully independent from the scheduler. A warehouse scheduled query may be independent of Airflow but still share the warehouse as a failure domain. Criticality should determine how far to separate the checker.

**Business invariants age.** A rule like `row_count >= 100` may detect a partial batch today and become wrong after a legitimate business change tomorrow. Deterministic does not mean timeless. Checks therefore need owners, versioning and review dates.

**A report can pass machine checks and still be semantically wrong.** For example, a source application may itself compute the wrong revenue amount while supplying a plausible batch date, row count and schema. Outcome observability reduces the unknown surface; it does not establish mathematical truth about the outside world. Cross-system reconciliation against an independent business source becomes necessary where that risk matters.

**Aggressive alert reduction has asymmetric downside.** The Voutsas study shows that ML filtering can perform well in a realistic cloud-monitoring setting, but the 2026 survey of security-alert screening highlights substantial production and generalization gaps. In a business process where one suppressed month-end financial batch is far more costly than hundreds of nuisance notifications, the appropriate operating point may be deliberately conservative. citeturn19view3turn20view0

**Full lineage can be excessive.** OpenLineage can provide powerful job/run/dataset correlation, but a four-step daily export may only need a case table, several SQL checks and an existing ticket/paging channel. The Google SRE monitoring chapter explicitly warns that monitoring systems themselves can become complex, fragile maintenance burdens and recommends simple, predictable rules. citeturn21view1

**Manual operation does not scale indefinitely.** Google SRE argues that repeated human procedures lose consistency and that automation offers a consistency advantage for well-scoped known tasks. The manual baseline is therefore a discovery and fallback mechanism, not necessarily the desired permanent architecture. citeturn16view0

### Contradictions worth preserving

There is a real tension between **noise reduction and case preservation**. Alerting platforms rightly provide deduplication, grouping, inhibition and suppression because notifying on every raw event is operationally expensive. Prometheus explicitly groups many alerts into a single notification, while PagerDuty applies matching dedup keys to an existing open alert. Neither mechanism knows whether two technical alerts correspond to one business problem or two independently owed deliveries. That semantic choice belongs to the process design. citeturn21view2turn16view2

There is also tension between **automation and clarity**. More automation can improve consistency; it can equally make a poorly specified rule fail consistently at scale. Google's SRE automation guidance states this trade-off explicitly. citeturn16view0

And there is tension between **faster automatic closure and trustworthy resolution**. PagerDuty permits an incident to enter `resolved`; the business system still needs to decide what constitutes actual repair. Automatically resolving on a successful rerun is reasonable only when the rerun's success signal itself includes the required business outcome evidence. PagerDuty's lifecycle semantics establish the incident distinction but not the domain-specific closure criterion. citeturn18view1

### Czech and US applicability

The core architecture does not materially differ between Czech and US teams. The meaningful variation is configuration: local business calendars, local deadlines, time zones, operating hours and escalation ownership.

For a Czech process, `Europe/Prague` should be part of the expectation rather than “UTC+1,” because civil-time offsets can change and daylight-saving rules are encoded in the IANA database. The same pattern applies to US processes: use the actual IANA business zone agreed for the process instead of inventing a country-wide fixed UTC offset. IANA's database is explicitly updated when political decisions change these rules. citeturn17view0

No evidence found in this research supports adding a Czech-versus-US distinction to the fundamental logic of expected-work reconciliation. Differences in privacy or sector regulation may matter for particular datasets, but they are outside the evidence needed to answer this observability decision and should not be forced into the design.

### Evidence and access gaps

No production systems, private customer data or user accounts were inspected. No alert was sent and no production repair was performed.

A PDF result for the original Dataflow Model paper was encountered during research, but the available web renderer did not recognize that result as a renderable PDF, so I did **not** silently infer detailed findings from it. Event-time versus processing-time claims in this dossier instead use the directly inspectable official Apache Flink documentation. The Dataflow paper is therefore not used as evidence for detailed claims.

Some ACM pages for alert-fatigue literature did not render successfully through the available web interface. Where relevant, I used an attributable institutional publication record for the peer-reviewed Voutsas et al. article and the inspectable May 2026 arXiv systematic-survey preprint. I have not represented inaccessible full-text sections as inspected evidence. citeturn19view3turn19view2

There is no strong primary comparative study located in this research that measures something like:

\[
\text{business incidents missed with job-only monitoring}
\quad\text{vs.}\quad
\text{business incidents missed with expected-work reconciliation}
\]

across organizations. The central recommendation is therefore an architecture synthesis supported by failure semantics and documented operational practices, not an experimentally established universal effect size.

## Reusable assets and publication angles

### Portable expected-work fixture and checker

The following asset is complete and uses only the Python standard library. Its numbers are **synthetic**.

It demonstrates five specific properties:

1. two consecutive affected business batches remain separate;
2. a stale report is detected despite a plausible successful upstream path;
3. a partial/bad transformation is detected despite an on-time report;
4. grouping preserves both case IDs;
5. failed notification receipt creates a separate transport problem rather than deleting the underlying cases.

```python
from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Optional
from zoneinfo import ZoneInfo


@dataclass(frozen=True)
class ExpectedWork:
    case_id: str
    business_date: str
    tz: str
    report_deadline_local: str
    owner: str
    min_rows: int


@dataclass(frozen=True)
class Evidence:
    source_arrived: bool
    raw_preserved: bool
    warehouse_business_date: Optional[str]
    warehouse_rows: int
    transform_failing_rows: int
    report_business_date: Optional[str]
    report_available_at_utc: Optional[str]


def deadline_utc(expected: ExpectedWork) -> datetime:
    """Convert the declared local business deadline to an absolute instant."""
    local = datetime.fromisoformat(
        expected.report_deadline_local
    ).replace(tzinfo=ZoneInfo(expected.tz))
    return local.astimezone(timezone.utc)


def reconcile(
    expected: ExpectedWork,
    observed: Optional[Evidence],
    now_utc: datetime,
) -> list[str]:
    """Return deterministic unresolved conditions for one business case."""
    problems: list[str] = []
    deadline = deadline_utc(expected)

    # Crucial silent-failure case:
    # the expected work exists even if no workflow observation exists.
    if observed is None:
        if now_utc >= deadline:
            problems += ["NO_OBSERVATION", "REPORT_DEADLINE_MISSED"]
        return problems

    if not observed.source_arrived:
        problems.append("SOURCE_MISSING")

    if not observed.raw_preserved:
        problems.append("RAW_NOT_PRESERVED")

    if observed.warehouse_business_date != expected.business_date:
        problems.append("WRONG_WAREHOUSE_PERIOD")

    # Synthetic threshold for this fixture, not a recommended universal rule.
    if observed.warehouse_rows < expected.min_rows:
        problems.append("WAREHOUSE_BELOW_MIN_ROWS")

    if observed.transform_failing_rows != 0:
        problems.append("BUSINESS_INVARIANT_FAILED")

    if observed.report_business_date != expected.business_date:
        problems.append("STALE_OR_WRONG_REPORT_PERIOD")

    if observed.report_available_at_utc is None:
        if now_utc >= deadline:
            problems.append("REPORT_DEADLINE_MISSED")
    else:
        report_time = datetime.fromisoformat(
            observed.report_available_at_utc
        )
        if report_time > deadline:
            problems.append("REPORT_DEADLINE_MISSED")

    return problems


def grouped_notification(
    open_cases: dict[str, list[str]]
) -> dict:
    """
    Reduce notification noise without throwing away individual
    business-case identities.
    """
    return {
        "group_key": "sales_daily_delivery",
        "affected_case_ids": sorted(open_cases),
        "case_count": len(open_cases),
    }


# ------------------------
# Synthetic expected work
# ------------------------

expected = [
    ExpectedWork(
        case_id="sales_daily:2026-10-08:Europe/Prague",
        business_date="2026-10-08",
        tz="Europe/Prague",
        report_deadline_local="2026-10-09T08:00:00",
        owner="analytics-oncall",
        min_rows=100,
    ),
    ExpectedWork(
        case_id="sales_daily:2026-10-09:Europe/Prague",
        business_date="2026-10-09",
        tz="Europe/Prague",
        report_deadline_local="2026-10-10T08:00:00",
        owner="analytics-oncall",
        min_rows=100,
    ),
    ExpectedWork(
        case_id="sales_daily:2026-10-10:Europe/Prague",
        business_date="2026-10-10",
        tz="Europe/Prague",
        report_deadline_local="2026-10-11T08:00:00",
        owner="analytics-oncall",
        min_rows=100,
    ),
]


# ------------------------
# Synthetic observations
# ------------------------

observed = {
    expected[0].case_id: Evidence(
        source_arrived=True,
        raw_preserved=True,
        warehouse_business_date="2026-10-08",
        warehouse_rows=120,
        transform_failing_rows=0,

        # Technical work happened, but the report serves yesterday's period.
        report_business_date="2026-10-07",
        report_available_at_utc="2026-10-09T05:30:00+00:00",
    ),

    expected[1].case_id: Evidence(
        source_arrived=True,
        raw_preserved=True,
        warehouse_business_date="2026-10-09",

        # Synthetic partial-load condition.
        warehouse_rows=60,
        transform_failing_rows=3,

        # Report is on time and labels the intended period,
        # but its underlying business result is invalid.
        report_business_date="2026-10-09",
        report_available_at_utc="2026-10-10T05:55:00+00:00",
    ),

    # 2026-10-10 has no observation yet, but is not due;
    # therefore it should not become an incident yet.
}


now = datetime(
    2026, 10, 10, 9, 0, tzinfo=timezone.utc
)

open_cases = {
    item.case_id: problems
    for item in expected
    if (
        problems := reconcile(
            item,
            observed.get(item.case_id),
            now,
        )
    )
}


# Group the two cases into one notification,
# but retain both identities.
notification = grouped_notification(open_cases)


# Synthetic transport result:
# the intended notification receiver did not confirm receipt.
transport_receipt = {
    "group_key": notification["group_key"],
    "attempted_at_utc": "2026-10-10T09:00:00+00:00",
    "accepted_by_receiver": False,
}

transport_problem = (
    ["ALERT_TRANSPORT_UNCONFIRMED"]
    if not transport_receipt["accepted_by_receiver"]
    else []
)


# ------------------------
# Executable assertions
# ------------------------

assert len(open_cases) == 2

assert (
    "STALE_OR_WRONG_REPORT_PERIOD"
    in open_cases[expected[0].case_id]
)

assert (
    "WAREHOUSE_BELOW_MIN_ROWS"
    in open_cases[expected[1].case_id]
)

assert notification["affected_case_ids"] == sorted(open_cases)

assert transport_problem == [
    "ALERT_TRANSPORT_UNCONFIRMED"
]


print("open_cases =", open_cases)
print("grouped_notification =", notification)
print("transport_problem =", transport_problem)
print("assertions_passed = 5")
```

### Firsthand execution record

I executed that synthetic checker during this research in an isolated Python environment. It touched no production services and made no network calls.

The result was:

```text
open_cases = {
  'sales_daily:2026-10-08:Europe/Prague':
    ['STALE_OR_WRONG_REPORT_PERIOD'],

  'sales_daily:2026-10-09:Europe/Prague':
    ['WAREHOUSE_BELOW_MIN_ROWS',
     'BUSINESS_INVARIANT_FAILED']
}

grouped_notification = {
  'group_key': 'sales_daily_delivery',
  'affected_case_ids': [
    'sales_daily:2026-10-08:Europe/Prague',
    'sales_daily:2026-10-09:Europe/Prague'
  ],
  'case_count': 2
}

transport_problem = ['ALERT_TRANSPORT_UNCONFIRMED']
assertions_passed = 5
```

**Executed test status:** five synthetic assertions passed.  
**Not tested:** Airflow, dbt, PagerDuty, Prometheus, OpenLineage, warehouse or BI integrations.  
**Not claimed:** any production reliability improvement, customer outcome, alert-volume reduction or recovery-time effect.

### Practical implementation sequence

For a team deciding what to automate, the highest-leverage sequence is:

**First, define the owed business result.** Write down case identity, business date, timezone, deadline, owner and actual resolution criteria.

**Second, run the reconciliation manually for several real cycles.** The purpose is to discover ambiguous source periods, exceptions, holidays, legitimate zero-volume days and ownership gaps—not to create permanent clerical toil.

**Third, standardize identifiers and evidence.** A stable `case_id`/batch ID should follow the process across source, warehouse, tests, report and case management where practical.

**Fourth, automate deterministic evidence collection.** Start with missing expected work, correct period/freshness, a small number of important invariants and the downstream result. Avoid constructing an observability cathedral before proving that three SQL queries and a case table are inadequate. Google's monitoring guidance explicitly favors simple, predictable rules and warns about monitoring-system complexity. citeturn21view1

**Fifth, add grouped actionable notifications.** Group interruptions but preserve business-case identity. Give each alert an owner, first action, escalation rule and machine-checkable closure condition. citeturn21view2

**Sixth, test recovery.** Preserve a source fixture, simulate stale/partial/missing cases, repair them and demonstrate that the reconciler distinguishes “recovered late” from “was always successful.” Google's data-integrity guidance similarly emphasizes demonstrating recovery capability rather than merely assuming it. citeturn17view4

**Only then add richer lineage or AI triage where investigation cost justifies it.** The evidence supports AI as a promising augmentation layer but does not justify treating it as the authoritative judge that an expected business obligation has been fulfilled. citeturn20view0

### Candidate distinct article angles

**“The automation is green. The report is wrong.”**  
The cleanest general-audience angle. Contrast technical completion with a stale or partial downstream result and introduce outcome reconciliation.

**“Monitor what should have happened—even when nothing happened.”**  
Focus on independent expected-work registries and the most important silent-failure class: the workflow that never exists.

**“One alert, two broken days.”**  
Use the deduplication scenario to explain why reducing notification noise must not erase independently affected business cases.

**“Acknowledged is not resolved.”**  
Build around the state ladder from notification receipt to human ownership, repair, deterministic verification and closure.

**“Before you automate the check, define ‘done.’”**  
Lead with the manual checklist and process-standardization argument. Useful for leaders choosing what to automate rather than observability specialists.

**“Let AI explain incidents, not decide reality.”**  
A more 2026-specific angle: deterministic detection/closure around a bounded AI triage layer, supported by the still-limited production evidence for AI alert screening. citeturn19view2turn20view0

### Useful article assets

The most reusable supporting assets from this dossier are the **expected-work schema**, **alert-to-action inventory**, **resolution-evidence matrix**, **two-batch deduplication scenario**, **portable Python checker**, and this compact outcome model:

```text
EXPECTATION
    ↓
OBSERVE
    ↓
RECONCILE
    ↓
CASE
    ↓
OWNER
    ↓
RECOVER
    ↓
RECONCILE AGAIN
    ↓
VERIFIED RESOLUTION
```

The editorial principle underneath all of them is:

> **A green automation answers “did the mechanism finish?” Outcome observability answers “did we receive the business result we were owed?”**

That distinction is consistent with externally visible/black-box monitoring, separate freshness and data assertions, explicit execution-state semantics and recovery-focused operational design in the inspected sources, while the concrete expected-work ledger architecture remains this dossier's synthesis. citeturn21view0turn21view4turn21view5turn21view6turn17view4

### Freshness triggers for this dossier

Recheck the dossier when **Airflow Deadline Alerts cease being experimental or change semantics**, because the current Airflow 3.3.2 documentation explicitly labels the feature experimental. citeturn21view3

Recheck dbt behavior after major dbt deployment/runtime changes because the source-freshness documentation was updated as recently as October 6, 2026 and configuration choices currently affect whether freshness failures stop subsequent work. citeturn18view5turn21view4

Recheck OpenLineage semantics when moving from version 1.53.0 or adopting new facets that encode higher-level quality/outcome evidence. citeturn21view6

Recheck PagerDuty/Prometheus deduplication, grouping and lifecycle behavior whenever those products are upgraded or routing policy changes. The recommendation relies on preserving individual business-case identity above whatever transport-level aggregation the current alerting platform performs. citeturn16view2turn21view2

Update installed IANA timezone data when the underlying platform distributes new tzdb versions; IANA's snapshot at inspection was 2026e and the database is explicitly revised as civil-time rules change. citeturn17view0

Revisit the AI-triage recommendation within roughly a year—or sooner after strong production studies in data operations—because the May 2026 review describes a rapidly evolving area with weak production and cross-environment validation relative to the volume of algorithmic work. citeturn19view2turn20view0

Most importantly, refresh the **business contract itself** whenever source semantics, report definitions, owners, business calendars, deadlines or accepted exceptions change. An observability system can faithfully evaluate yesterday's definition of “done” and still be wrong for today's business; that is the maintenance cost no telemetry product can automate away.