fix(latest,web): finish the atomic deletion and honest empty states (#145)

Review fixes on top of cb2b104:
- Delete the write-only in-memory refuseUntil map and setRefusalBackoff now
  that status.go is gone: the pass gate reads the durable stamp, so the map
  was half-deleted dead state (spec review C-1).
- An outcome-query failure no longer blanks the Lane table into the false
  'no data yet': rows render with 'none observed' chips instead (I-1).
- due-query and eligible-count skips get their own sentences instead of the
  merged 'check failed' (I-2).
- ADR-0012 constrain wording corrected and trailing newline added (M-1)
This commit is contained in:
2026-08-21 20:31:50 +07:00
parent cb2b104e63
commit fc8a40cfc6
3 changed files with 17 additions and 25 deletions
+3 -15
View File
@@ -57,11 +57,12 @@ type Poller struct {
// refuseUntil gates a Site's Lane after it refused twice in one run: no
// Series of that Site is attempted again before this time (issue #100).
// The stamp is durable — the pass gate reads it from the store, so a
// restart does not forget the refusal; nothing of it lives in memory.
// browserDownAt is when a browser Lane last lost the sidecar; the other
// browser Lanes skip their passes for the next RefuseBackoff, so a
// restarting Chrome does not stamp one Series per pass per Lane (story 20).
mu sync.Mutex
refuseUntil map[string]time.Time
browserDownAt time.Time
// coverWG tracks in-flight cover work. Covers heal in the background so a
// slow cover host cannot delay the next Series-page Poll; tests join it
@@ -437,12 +438,8 @@ func (p *Poller) runLanePass(ctx context.Context, name string, paced bool) time.
log.Printf("latest poll %s: due=%d checked=%d", name, len(due), fig.Checked)
}
if refusals >= 2 {
p.setRefusalBackoff(name, now.Add(RefuseBackoff))
// The refusal outlives the process: the durable stamp gates a restart,
// so a Site that just told us to back off is not re-probed. The
// in-memory twin is still written because the Lane status block reads
// it directly; the gate reads the durable stamp, so a restart does not
// forget the refusal.
// so a Site that just told us to back off is not re-probed.
if err := p.Store.SetLaneRefusal(name, now.Add(RefuseBackoff).UnixMilli()); err != nil {
log.Printf("latest poll %s: persist refusal: %v", name, err)
}
@@ -511,15 +508,6 @@ func (p *Poller) countEligible(site string) (int, error) {
return p.Store.EligibleSeriesCount(site)
}
func (p *Poller) setRefusalBackoff(name string, until time.Time) {
p.mu.Lock()
defer p.mu.Unlock()
if p.refuseUntil == nil {
p.refuseUntil = make(map[string]time.Time)
}
p.refuseUntil[name] = until
}
// setBrowserDown records when a browser Lane lost the sidecar. It is Poller
// state rather than pass state so the other browser Lanes see it too.
func (p *Poller) setBrowserDown(now time.Time) {