Some of my agenda files use custom TODO keywords (set through a
#+SETUPFILE), and some use the standard TODO | DONE keywords. I recently discovered that TODO blocking is broken in the files which use custom keywords.
It turns out the org-not-done-heading-regexps variable was global instead of buffer-local like the other *-regexp variables; this appears to be due to a typo in org.el.
I think the blocker hook (org-block-todo-from-children-or-siblings-or-parent) was picking up the global value (set by one of the "factory-default" buffers, which got opened last) and applying it to buffers with my custom TODO keywords, so it was not correctly identifying some headlines as TODO headlines.
The patch below corrects the typo and fixes TODO blocking in my custom-keyword files. I hope you find it useful. (BTW, I quickly ran through the other make-variable-buffer-local invocations in org.el, and didn't see any more typos of this nature.)
diff --git a/lisp/org.el b/lisp/org.el
index 97b5365..985dd74 100644
@@ -4602,7 +4602,7 @@ Otherwise, these types are allowed:
(defvar org-not-done-heading-regexp nil
"Matches a TODO headline that is not done.")
(defvar org-todo-line-regexp nil
"Matches a headline and puts TODO state into group 2 if present.")