ReadonlybyThe deepest history any spec of a given op needed, by op name.
Not per spec: sma(5) and sma(100) in one plan collapse to
{ sma: 99 }. That is a diagnostic aid for explain-style output,
not something to slice against — rows is the number a caller
uses. The doc previously said "per-spec depth … keyed by op name",
which is self-contradictory and was flagged in review.
ReadonlyknownFalse when any op in the plan does not declare a lookback.
Optional ReadonlyrowsRows of history the plan needs before a requested range. Present only when known — there is no safe default to report.
ReadonlyundeclaredOps with no declared lookback, deduplicated, in encounter order.
The minimum safe tail for a plan, in rows — [PND-PROCHIST].
Why this is not the consumer's call
The hot leading edge is the design's worst cliff: an 8-study stack over 500k rows costs 765 ms/tick, saturating at ~1.3 ticks/sec. The same stack over a 5,000-row tail runs at 5.4 ms/tick. So a consumer watching a live edge should slice, and the only question is where.
The RFC left that to the consumer. It should not be a guess in either direction: too short silently truncates a study's warm-up and reports
undefinedwhere a value exists, too long gives the cliff back. The registry already knows every op's lookback, sodisplay range + requiredHistory(plan)is provably sufficient.Lookbacks sum along a chain; they do not max
This is the part worth getting right.
sma(20)oversma(50)does not need 50 rows of history — it needs 50 for the inner study to produce anything, and then a further 19 rows of that output before the outer one does. 69, not 50. Taking the max across a nested chain under-provisions by exactly the amount that makes the bug subtle: the answer is defined, plausible, and computed from a truncated window.Across independent specs in a plan it is a max, because the plan needs whichever branch reaches furthest back.
Unknown is not zero
An op that does not declare
lookbackmakes this return{ known: false }with the offending ops named, rather than a number. A missing declaration and a genuinely element-wise op are the same value and opposite meanings, and defaulting to zero would hand back a confidently wrong slice. An element-wise op should declare() => 0.