#6601·beads

is_blocked: a sub-epic close-gated under an exogenously blocked epic keeps its children visible (follow-up to #6506)

Author: bee-ghosttrackCreated Sep 18, 2026Updated Sep 18, 2026

Follow-up to #6506 (the parent-child cascade fix, which lands with a PR referencing this issue).

The shape

E  --blocks-->  X        (X open, NOT in E's subtree: E is exogenously blocked)
S  parent-child  E       (S is a sub-epic under E)
S  --blocks-->  C1, C2   (S close-gates its own children)
C1, C2  parent-child  S

Under the #6506 contract, E's exogenous blockedness should cascade E → S → C1, C2, so C1 and C2 read blocked. With the fix as landed, S is blocked both by its own children (a close gate, which must NOT darken them) and by its exogenously blocked parent (which must). The exogeneity predicate decides S's blockedness for its children by looking at S's own outgoing reasons, and S's own reasons are all inside its subtree — so S reads "blocked only by its own subtree" and C1/C2 stay visible where the contract darkens them.

Why it was left

  • Both the incremental write path and the full repair (RecomputeAllIsBlockedInTx) agree on this shape: no inconsistency, no oscillation, bd doctor reports 0.
  • The deviation is in the safe direction: work is shown, never hidden. The pre-fix behavior hid work by construction.
  • Closing it needs either a second stored bit (exogenously-blocked, distinct from is_blocked) or a recursive walk that the batch-scoped templates cannot splice today (#6288 shape).

It is named in the CHANGELOG entry for #6506 as a known limitation.

What a fix looks like

Carry "exogenously blocked" as its own derived value per parent (a second column or a second fixpoint leg), so a parent's children inherit the ancestor's exogenous cause even when the parent's own reasons are all endogenous. A pinned test for the shape above (C1/C2 blocked) should go red on today's main and green on the fix.