Class: Textus::Domain::Lifecycle

Inherits:
Object
  • Object
show all
Defined in:
lib/textus/domain/lifecycle.rb

Overview

Unified lifecycle reporter (ADR 0079): which entries are past their ttl, and the on_expire action that applies. Replaces both Staleness::IntakeCheck and Retention. Age basis: _meta.last_fetched_at (intake) when present, else file mtime (stored). ‘self.verdict` is the pure per-entry decision that BOTH this reporter and `Read::Get` (Plan 2) call, so the basis logic lives once.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(manifest:, file_stat:, clock:) ⇒ Lifecycle

Returns a new instance of Lifecycle.



31
32
33
34
35
# File 'lib/textus/domain/lifecycle.rb', line 31

def initialize(manifest:, file_stat:, clock:)
  @manifest  = manifest
  @file_stat = file_stat
  @clock     = clock
end

Class Method Details

.parse_time(str) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/textus/domain/lifecycle.rb', line 23

def self.parse_time(str)
  return nil if str.nil?

  Time.parse(str.to_s)
rescue ArgumentError, TypeError
  nil
end

.verdict(policy:, last_fetched_at:, mtime:, now:) ⇒ Object

Pure: is the entry past its ttl? -> [expired(bool), reason(String|nil)].



12
13
14
15
16
17
18
19
20
21
# File 'lib/textus/domain/lifecycle.rb', line 12

def self.verdict(policy:, last_fetched_at:, mtime:, now:)
  ttl = policy.ttl_seconds
  return [false, nil] if ttl.nil?

  basis = parse_time(last_fetched_at) || mtime
  return [true, "never recorded"] if basis.nil?

  age = (now - basis).to_i
  age > ttl ? [true, "ttl exceeded (age=#{age}s, ttl=#{ttl}s)"] : [false, nil]
end

Instance Method Details

#call(prefix: nil, zone: nil) ⇒ Object



37
38
39
40
41
# File 'lib/textus/domain/lifecycle.rb', line 37

def call(prefix: nil, zone: nil)
  @manifest.data.entries
           .select { |m| entry_matches?(m, prefix: prefix, zone: zone) }
           .flat_map { |m| rows_for(m) }
end