Summary
pv status and pv doctor treat every failed job among the last 100 records as a current whole-system failure. Plain status output omits the stored timestamps. A transient failure can therefore make PV appear broken for days—even after the underlying operation succeeds or the system is repaired.
Stale runtime observations compound the problem because a successful privileged repair such as pv ports:install does not necessarily produce a newer Gateway observation.
Verified incident behavior
The live database had 18 total jobs. Seven historical failures included:
- two expected lock conflicts during the real app update;
- multiple 60-second Gateway readiness failures caused by missing PF routing;
- one reconciliation abandoned during daemon restart;
- one transient
pv.db-wal race.
After pv ports:install restored ai.test to HTTP 200 and pv update --check reported everything current:
pv status --json still returned overall: failed;
- the old failed Gateway observation remained current in persisted runtime state;
- every historical failed job still appeared under
recent_errors;
pv doctor failed Recent jobs and recommended broad pv setup.
Current code
StatusSnapshot::read filters all failed records returned by recent_jobs() and makes any non-empty result fail aggregate health: status.rs.
The database returns the most recent 100 jobs without supersession semantics: database.rs.
Plain output prints the job identity/error but omits started_at and finished_at: status.rs.
Doctor independently fails if any recent job failed: doctor.rs.
Expected behavior
Historical failures should remain available as diagnostics, but aggregate current health should reflect unresolved/current failures rather than the mere existence of any failure in a fixed-size history window.
The exact supersession/recency policy should be made explicit before implementation.
Acceptance criteria
- Define current-versus-historical failure semantics in
DESIGN.md.
- A newer successful operation or verified repaired current state can supersede an older failure for aggregate health.
- Superseded failures remain visible in job history without forcing
overall: failed.
- A genuinely unresolved latest failure still produces non-zero status/doctor results.
- Plain output includes enough timestamp/age context to prevent old errors from looking current.
- A successful focused repair either refreshes affected observations or clearly marks older observations as stale/history.
- Status and doctor apply the same current-health policy.
- Add integration coverage for failure → repair/success → healthy aggregate status while preserving historical diagnostics.
Related
Summary
pv statusandpv doctortreat every failed job among the last 100 records as a current whole-system failure. Plain status output omits the stored timestamps. A transient failure can therefore make PV appear broken for days—even after the underlying operation succeeds or the system is repaired.Stale runtime observations compound the problem because a successful privileged repair such as
pv ports:installdoes not necessarily produce a newer Gateway observation.Verified incident behavior
The live database had 18 total jobs. Seven historical failures included:
pv.db-walrace.After
pv ports:installrestoredai.testto HTTP 200 andpv update --checkreported everything current:pv status --jsonstill returnedoverall: failed;recent_errors;pv doctorfailedRecent jobsand recommended broadpv setup.Current code
StatusSnapshot::readfilters all failed records returned byrecent_jobs()and makes any non-empty result fail aggregate health:status.rs.The database returns the most recent 100 jobs without supersession semantics:
database.rs.Plain output prints the job identity/error but omits
started_atandfinished_at:status.rs.Doctor independently fails if any recent job failed:
doctor.rs.Expected behavior
Historical failures should remain available as diagnostics, but aggregate current health should reflect unresolved/current failures rather than the mere existence of any failure in a fixed-size history window.
The exact supersession/recency policy should be made explicit before implementation.
Acceptance criteria
DESIGN.md.overall: failed.Related
pv updateincurs a 10-second launchd throttle after switching app binary #300