name:
Layer refactor
overview:
Refactor cron layers into shared, configurable primitives so each layer composes selection, gating (updated-since / stalest), and Beeminder dispatch without duplicating logic.
todos:
id:
layer-pipeline
content:
Create shared layer pipeline module + types
status:
completed
id:
state-generalize
content:
Generalize last-run and snapshot storage by jobId
status:
completed
id:
cron-refactor
content:
Refactor three cron files to use pipeline
status:
completed

Flexible Layer Design

Goals

  • Make layer behavior composable: selector (which issues), gate (when to count), and sink (Beeminder send + daily de-dupe) should be reusable.
  • Keep separate cron entrypoints while sharing logic and storage helpers.

Proposed Architecture

  • Introduce a small “layer pipeline” module that exposes:
    • collectUpdatedIssues(...) (shared fetch + last-run handling)
    • filterByLabels(...) (subset selection for tagged rules)
    • gateByStalestPrefix(...) (oldest/stalest gating using snapshot table + temporal ordering)
    • sendBeeminderDatapoints(...) (daily de-dupe + comment + dispatch)
  • Keep each cron thin: define layer config (selector + gate + goal routing), then call the pipeline.

Targeted Code Touchpoints

Data Flow (Mermaid)

Rendering mermaid diagram...

Notes on Flexibility

  • Gate composition allows “only-oldest” to apply to any selector (e.g., tagged subset) without duplicating query logic.
  • Snapshot storage becomes keyed by jobId so multiple layers can persist their own “stalest prefix”.
  • Stalest gating enforces temporal order using issue.updated_at: process the stalest prefix in order and only emit a contiguous run of updated issues (if the first stale item is unchanged, stop).

Risks

  • Table schema updates require new table names per Val Town rules; plan includes new tables (e.g., _1 suffix) where needed.