Screener Ripeness — Lifecycle Stages & the Buy-Zone Gate
Last verified
Sibling reading: The Screener System (S1 → S2 → S3 vision) and Screener Pipeline & Lifecycle (the operational lifecycle). This article covers ripeness — the one classifier that decides whether a name has seasoned into its historically-good entry zone, and the two views built on top of it.
What ripeness is
A name firing on the screener is not the same as a name worth acting on. An archetype can flag a ticker on day 1 (brand new, unconfirmed), watch it persist for a week (seasoning), or hold it so long the early-entry edge has decayed (too late). Ripeness is the single classifier that reads where a candidate sits in that lifecycle and labels it with one of seven stages.
There is one pure classifier, two views (design doctrine P12 — graduate by tier):
- The
/screenerworkbench shows every firing name with its ripeness stage — the full lifecycle, including names that are too fresh, not yet convicted, late, or stale. - The Tape Company Action Board shows only the ripe elite — the names at stage
confirmedorloaded.
Ripeness is a CONTEXT / triage classification, never advice. “Ripe” means “persisted into the historically-good entry zone, with conviction” — it is not a directive to buy.
The classifier lives in app/screener/ripeness.py (classify_ripeness). All thresholds are operator-tunable in screener_config.json § ripeness — there are no magic numbers in code.
The seven stages
Stages are evaluated in order; the first matching rule wins. day is the candidate’s days_on_list; window is the archetype’s relevance window (screener_config.json § lifecycle.relevance_windows); cutoff = ripe_window_frac × window is the buy-zone time boundary.
| Stage | Condition | What it means |
|---|---|---|
unknown |
ABSTAIN — status, day, or window missing/invalid (or window ≤ 0) |
Not enough lifecycle data to classify. A data hole never fakes a ripe setup. |
stale |
terminal status (decayed / exited), or day > window |
The candidacy is over, or relevance has elapsed. |
fresh |
status == new |
Brand-new flag, awaiting confirmation. Not yet actionable. |
building |
status == persisting, in the buy zone by time (day ≤ cutoff), but conviction below min_conviction_tier (or a required state not yet met) |
Alive and seasoning, not yet convicted. Stays off the Tape. |
late |
status == persisting and day > cutoff |
Still on the list, but entry is too far along — the early-entry edge has decayed. |
confirmed |
status == persisting, day ≤ cutoff, conviction ≥ min_conviction_tier (and state == require_state when that gate is set), and state != primed |
RIPE. Persisted into the buy zone with conviction. |
loaded |
same as confirmed, plus state == primed |
RIPE — strongest. Confirmed and the archetype engine is fully primed. |
ripe == true only for confirmed and loaded (the module-level _RIPE_STAGES constant is the single source of truth — ripeness is derived mechanically, never passed in per-call).
The buy-zone gate
A candidate is ripe when all of these hold:
- Persisting —
status == persisting(survived past the brand-newfreshday, not yet decayed/exited). - In the buy zone by time —
day ≤ ripe_window_frac × window. The early part of an archetype’s relevance window is where the historical edge concentrates; pastcutoffthe name readslate. - Convicted —
conviction_tier ≥ min_conviction_tier(high > medium > low). Below it, the name readsbuilding. - State gate (optional) — if
require_stateis set, the archetypestatemust match it.
confirmed vs loaded is the same gate; loaded simply adds that the engine state is primed (strongest conviction). Both are ripe.
The three tunable thresholds
All in screener_config.json § ripeness. A missing or malformed block falls back to the code defaults (0.66 / medium / no state gate).
| Key | Default | Effect |
|---|---|---|
ripe_window_frac |
0.66 |
Buy-zone cutoff as a fraction of the relevance window. A persisting name is eligible for confirmed only while days_on_list ≤ ripe_window_frac × window; past that it is late. 0.66 = the first two-thirds of the window. |
min_conviction_tier |
medium |
Minimum conviction to reach confirmed. medium admits high + medium; high admits only high; low admits all. A persisting, in-window name below this tier reads building. |
require_state |
null |
Optional engine-state gate (null / partial / primed). When set, confirmed additionally requires state to match. null = no requirement — a primed name is still labeled loaded, but primed is not required for ripeness. |
Progress, day, and window
The classifier returns {stage, ripe, day, window, progress, reasons}:
day—days_on_list, the candidacy day counter.window— the archetype’s relevance window in trading days.progress—round(day / window, 4), the “line filling out” toward the end of relevance (ornullwhen uncomputable). It can briefly exceed1.0on the day a name tips intostale.reasons— a human-readable list explaining the verdict (always a list, never null;confluence_countis appended on ripe verdicts when present).
The two views in the UI
/screener (the workbench) — every firing name, full lifecycle:
- A ripeness column with the stage chip and a
day / windowbuy-zone progress bar, plus a “Ripe only” filter (?ripe_only=1) that isolates exactly the Tape-eligible set (R2). - A per-company lifecycle timeline and a graduated funnel (Fired → S1 signal → S2 deep set → Promoted) on
/screener/<ticker>(R3). - A Realized Episodes overlay on
/screener/<ticker>— each completed candidacy graded as a hindsight “would-have” trade (R3b), so you can see how ripe setups actually resolved for that name.
The Tape Company Action Board — only confirmed + loaded names. Because the gate is selective, the board is sometimes sparse or empty, and that is correct: when nothing is ripe, the honest answer is an empty board. Picks are never manufactured to fill slots.
Related
- The Screener System — the S1 → S2 → S3 vision the ripeness gate sits on top of.
- Screener Pipeline & Lifecycle — the operational lifecycle (
new→persisting→decayed/exited/promoted). - Live: the Screener workbench and the Company Action Board on the Tape.