A block that is not needed reports dormant in three situations the status cannot tell apart: its last evaluation is still current, its own state changed after that evaluation, or it has never been evaluated. Only an upstream change turns it stale (#310). A consumer that reads dormant as "up to date" is wrong in the second and third case, and the block's descendants inherit the error, since a dormant upstream counts as fine.
Repro
Against main at 366150a, with only data on screen:
library(shiny)
library(blockr.core)
options(blockr.background_construction_delay = 0)
board <- new_board(
blocks = c(
data = new_dataset_block("iris"),
a = new_subset_block(subset = "Sepal.Length > 5"),
b = new_head_block()
),
links = c(new_link("data", "a", "data"), new_link("a", "b", "data"))
)
testServer(
get_s3_method("board_server", board),
{
report <- function(step) {
status <- vapply(c("a", "b"), function(id) reval_if(rv$eval[[id]]), "")
res <- rv$blocks$a$server$result()
cat(
format(step, width = 30), paste(names(status), status, sep = "=", collapse = " "),
" a$result():", if (is.null(res)) "NULL" else paste(dim(res), collapse = "x"), "\n"
)
}
show <- function(on) {
for (id in c("a", "b")) {
vis$required[[id]](on)
vis$visible[[id]](on)
}
session$flushReact()
}
session$flushReact()
report("never shown")
show(TRUE)
report("on screen")
show(FALSE)
report("off screen again")
board_update(list(blocks = list(mod = list(a = list(subset = "Sepal.Length > 7")))))
session$flushReact()
report("a's own subset edited")
board_update(list(blocks = list(mod = list(data = list(dataset = "mtcars")))))
session$flushReact()
report("upstream dataset changed")
},
args = list(
x = board,
callbacks = function(visibility, ...) {
visibility$required[["data"]](TRUE)
visibility$visible[["data"]](TRUE)
}
)
)
never shown a=dormant b=dormant a$result(): NULL
on screen a=ready b=ready a$result(): 118x5
off screen again a=dormant b=dormant a$result(): NULL
a's own subset edited a=dormant b=dormant a$result(): NULL
upstream dataset changed a=stale b=stale a$result(): NULL
After a's subset is edited off screen, both a and b are out of date and both read dormant. The first line is the never-run case, which reads the same. (The NULL results are a separate gap, filed next to this one.)
Cause
The input_stale reactive (block-server.R#L323-L375) compares only what each upstream produced against what the block consumed from it. It never looks at the block's own expression, and it returns FALSE outright when the block has no previous evaluation (#L344-L346). Issue #318 recorded the first gap ("a change to the block's own expression is not staleness") and answered it with the evaluate and sustain requests. Those let a consumer force a run, but not tell which blocks need one.
Suggested direction
Extend input_stale to the block's own side of the key the unchanged-inputs skip already uses (#L412-L418): compare the current expression against the one in last_eval by the same identity test, and the eval trigger by value, as the skip does. An own edit then reads stale, and the existing upstream check carries it down the cone. A block with no previous evaluation gets a status of its own, say unevaluated, which propagates downstream like stale does. With that, dormant means one thing: not evaluated now, and nothing it depends on has changed since it was.
The immediate consumer is the assistant's commit review (BristolMyersSquibb/blockr.assistant#165). It needs to know whether a change it just made broke a block the user cannot see. With these statuses it would request a one-off evaluate for whatever reads stale or unevaluated, wait until none does, and read the rest as current. Today a one-off run ends in dormant, which cannot be told from never having run, so it holds a sustain claim over the edited blocks instead (BristolMyersSquibb/blockr.assistant#164).
A block that is not needed reports
dormantin three situations the status cannot tell apart: its last evaluation is still current, its own state changed after that evaluation, or it has never been evaluated. Only an upstream change turns itstale(#310). A consumer that readsdormantas "up to date" is wrong in the second and third case, and the block's descendants inherit the error, since adormantupstream counts as fine.Repro
Against
mainat 366150a, with onlydataon screen:After
a's subset is edited off screen, bothaandbare out of date and both readdormant. The first line is the never-run case, which reads the same. (TheNULLresults are a separate gap, filed next to this one.)Cause
The
input_stalereactive (block-server.R#L323-L375) compares only what each upstream produced against what the block consumed from it. It never looks at the block's own expression, and it returnsFALSEoutright when the block has no previous evaluation (#L344-L346). Issue #318 recorded the first gap ("a change to the block's own expression is not staleness") and answered it with theevaluateandsustainrequests. Those let a consumer force a run, but not tell which blocks need one.Suggested direction
Extend
input_staleto the block's own side of the key the unchanged-inputs skip already uses (#L412-L418): compare the current expression against the one inlast_evalby the same identity test, and the eval trigger by value, as the skip does. An own edit then readsstale, and the existing upstream check carries it down the cone. A block with no previous evaluation gets a status of its own, sayunevaluated, which propagates downstream likestaledoes. With that,dormantmeans one thing: not evaluated now, and nothing it depends on has changed since it was.The immediate consumer is the assistant's commit review (BristolMyersSquibb/blockr.assistant#165). It needs to know whether a change it just made broke a block the user cannot see. With these statuses it would request a one-off
evaluatefor whatever readsstaleorunevaluated, wait until none does, and read the rest as current. Today a one-off run ends indormant, which cannot be told from never having run, so it holds asustainclaim over the edited blocks instead (BristolMyersSquibb/blockr.assistant#164).