Skip to content

Discriminate Failed vs Empty Probe Cycles in run_cycle #46

@henry0816191

Description

@henry0816191

Problem

The eval (Test 10) found that run_cycle conflates failed and empty probe cycles — a cycle that returns zero results because no new papers match the criteria is indistinguishable from a cycle that failed due to a network error, API timeout, or malformed response. Both produce the same return path. This is the core of the "Silent-Staleness Cascade" compound identified in the eval: when a probe cycle fails silently, the system falls back to stale data, and the operator cannot distinguish a genuine "no new papers" result from a failure that has stopped the pipeline. The health endpoint compounds this — it reports the last cycle's status but cannot tell the operator whether that status is genuine.

Acceptance Criteria

  • run_cycle return type updated to a discriminated result (e.g., a dataclass/enum with Success(results=[...]), Empty(), and Failed(error=...) variants)
  • Callers of run_cycle updated to handle all three variants explicitly
  • Logging distinguishes between the three outcomes: successful cycle with N results, empty cycle (no matching papers), and failed cycle (with error detail)
  • Metrics/counters (if any) track the three outcomes separately
  • Health endpoint (if it reads cycle status) reports the discriminated result, not just "last run succeeded"
  • Tests cover all three variants: successful, empty, and failed cycles
  • Tests pass in CI (if applicable)
  • PR approved by at least 1 reviewer

Implementation Notes

The simplest approach is a CycleResult dataclass with a status enum field (SUCCESS, EMPTY, FAILED) and optional results and error fields. The existing run_cycle function likely catches exceptions and returns an empty list — change this to return CycleResult(status=FAILED, error=str(e)) in the except block and CycleResult(status=EMPTY) when the probe returns zero results legitimately. This fix also addresses the "opaque failure path" planned item where config errors retry as transient — with a discriminated result, config errors can be classified as FAILED with a non-retriable error type.

References

  • Eval finding: Test 10 (run_cycle conflates failed and empty cycles)
  • Related files: run_cycle function (likely in src/scheduler.py or src/core.py), health endpoint handler, test files for cycle logic

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No fields configured for Task.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions