Hi Charles,

Thanks for reporting this, and sorry it’s taken so long for someone to respond (it’s been a busy year for the maintainers).

I’ve confirmed both your issue report (thanks for the detailed steps), and your suggested fix. As such, I’ve produced a patch (attached). It would be good if someone else could check this looks fine and apply it.

All the best,
Timothy

From: Charles Tam
Subject: Bug: org-agenda-sort-notime-is-late is not correctly handled by timestamp comparison [9.4.6 (9.4.6-12-gdcc3a8-elpaplus @ /Users/charlestam/.emacs.d/elpa/org-plus-contrib-20210830/)]
To: emacs-orgmode@gnu.org
Date: Thu, 02 Sep 2021 12:47:19 +0800

org-agenda-sorting-strategy claims that scheduled-up (-down) causes
items to be sorted in ascending (descending) order by scheduled
timestamp.

org-agenda-sort-notime-is-late claims that if it is non-nil, the absence
of a timestamp is treated as being maximal.

Instead, when using the scheduled-up (-down) sorting strategy, with
non-nil org-agenda-sort-notime-is-late, the absence of a timestamp is
treated as being minimal. Note that the documentation is not strictly
wrong; the correct behavior is exhibited for time-of-day comparisons,
just not timestamp comparisons.

Steps to Reproduce:

  (setq org-agenda-sorting-strategy '((agenda scheduled-up)
                                      (todo scheduled-up)
                                      (tags scheduled-up)
                                      (search scheduled-up))
        org-agenda-sort-notime-is-late t)

  Place the following text in an org agenda file:

  * Reproduce ordering bug
  ** TODO Early item
     SCHEDULED: <1990-01-01 Mon>
  ** TODO Late item
     SCHEDULED: <2020-01-01 Wed>
  ** TODO Unscheduled item

  (Replace TODO with any non-DONE todo state if you need to.)
 
  Place the point on the "Reproduce" item and `M-x org-agenda < < t`
  (that is, list all TODO items restricted to the "Reproduce" subtree).

Expected:

  TODO Early item
  TODO Late item
  TODO Unscheduled item

Actual:

  TODO Unscheduled item
  TODO Early item
  TODO Late item

Suggested fix:

  Find `defsubst org-cmp-ts` in org-agenda.el. The definition of `def`
  in the `let*` should be something like

  (if org-agenda-sort-notime-is-late 99999999 -1)

(In the state dump below, `org-agenda-sort-notime-is-late` is not mentioned but has its default value of t.)

Thanks,
Charles

Emacs  : GNU Emacs 27.2 (build 1, x86_64-apple-darwin18.7.0, NS appkit-1671.60 Version 10.14.6 (Build 18G95))
 of 2021-03-27
Package: Org mode version 9.4.6 (9.4.6-12-gdcc3a8-elpaplus @ /Users/charlestam/.emacs.d/elpa/org-plus-contrib-20210830/)

current state:
==============
(setq
 org-roam-db-location "/Users/charlestam/mise/roam/org-roam.db"
 org-src-mode-hook '(org-src-babel-configure-edit-buffer org-src-mode-configure-edit-buffer)
 org-after-todo-state-change-hook '(org-checklist)
 org-capture-prepare-finalize-hook '(org-roam-capture--install-finalize-h)
 org-link-shell-confirm-function 'yes-or-no-p
 org-expiry-wait "+30d"
 org-metadown-hook '(org-babel-pop-to-session-maybe)
 org-clock-out-hook '(org-clock-remove-empty-clock-drawer)
 org-roam-db-node-include-function #[0 "\300\207" [t] 1]
 org-refile-targets '((nil :maxlevel . 2) (org-agenda-files :maxlevel . 1))
 org-html-format-inlinetask-function 'org-html-format-inlinetask-default-function
 org-pretty-entities t
 org-special-ctrl-a/e t
 org-agenda-files '("~/mise/TODO")
 org-ascii-format-inlinetask-function 'org-ascii-format-inlinetask-default
 org-reveal-start-hook '(org-decrypt-entry)
 org-modules '(org-expiry org-habit ol-w3m ol-bbdb ol-bibtex ol-docview ol-gnus ol-info ol-irc ol-mhe ol-rmail
               ol-eww)
 org-startup-folded 'showall
 org-archive-location "%s_archive::datetree/"
 org-mode-hook '((lambda nil (font-lock-add-keywords nil '(("{{{.+}}}" 0 'org-macro-face))) (set-fill-column 92))
                 #[0 "\300\301\302\303\304$\207" [add-hook change-major-mode-hook org-show-all append local] 5]
                 #[0 "\300\301\302\303\304$\207"
                   [add-hook change-major-mode-hook org-babel-show-result-all append local] 5]
                 org-babel-result-hide-spec org-babel-hide-all-hashes
                 #[0 "\301\211 \207" [imenu-create-index-function org-imenu-get-tree] 2] turn-on-font-lock
                 auto-fill-mode org-eldoc-load)
 org-tags-match-list-sublevels nil
 org-archive-hook '(org-attach-archive-delete-maybe)
 org-confirm-elisp-link-function 'yes-or-no-p
 org-agenda-before-write-hook '(org-agenda-add-entry-text)
 org-metaup-hook '(org-babel-load-in-session-maybe)
 org-bibtex-headline-format-function #[257 "\300 \236A\207" [:title] 3 "\n\n(fn ENTRY)"]
 org-latex-format-drawer-function #[514 "\207" [] 3 "\n\n(fn _ CONTENTS)"]
 org-expiry-handler-function 'org-toggle-archive-tag
 org-agenda-deadline-faces '((1.0 . org-warning) (0.8 . org-imminent-deadline) (0.5 . org-upcoming-deadline)
                             (0.0 . org-upcoming-distant-deadline))
 org-babel-pre-tangle-hook '(save-buffer)
 org-tab-first-hook '(org-babel-hide-result-toggle-maybe org-babel-header-arg-expand)
 org-hide-leading-stars t
 org-babel-load-languages '((python . t))
 org-log-done 'time
 org-roam-capture-preface-hook '(org-roam-dailies--override-capture-time-h)
 org-hide-emphasis-markers t
 org-export-backends '(ascii html latex md)
 org-roam-completion-everywhere t
 org-roam-capture-templates '(("d" "default" plain "%?" :target
                               (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: \n")
                               :unnarrowed t)
                              ("t" "task" entry "* NONE %?" :target
                               (file+head+olp "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+filetags: \n"
                                ("Action Items"))
                               )
                              )
 org-checklist-export-function 'org-export-as-ascii
 org-ascii-format-drawer-function #[771 " \207" [] 4 "\n\n(fn NAME CONTENTS WIDTH)"]
 org-agenda-span 10
 org-agenda-loop-over-headlines-in-active-region nil
 org-src-lang-modes '(("redis" . redis) ("php" . php) ("arduino" . arduino) ("C" . c) ("C++" . c++)
                      ("asymptote" . asy) ("bash" . sh) ("beamer" . latex) ("calc" . fundamental) ("cpp" . c++)
                      ("ditaa" . artist) ("dot" . fundamental) ("elisp" . emacs-lisp) ("ocaml" . tuareg)
                      ("screen" . shell-script) ("shell" . sh) ("sqlite" . sql))
 org-roam-db-autosync-mode-hook '(vulpea-db-autosync-enable)
 org-agenda-clock-consistency-checks '(:max-duration "10:00" :min-duration 0 :max-gap "0:05" :gap-ok-around
                                       ("4:00") :default-face org-agenda-clock-gap :overlap-face nil :gap-face
                                       nil :no-end-time-face nil :long-face nil :short-face nil)
 org-roam-find-file-hook '(org-roam-buffer--setup-redisplay-h org-roam--register-completion-functions-h
                           org-roam--replace-roam-links-on-save-h org-roam-open-id-with-org-roam-db-h
                           org-roam-db-autosync--setup-update-on-save-h)
 org-agenda-prefix-format '((agenda . " %i %?-12t% s") (todo . " %i ") (tags . " %i ") (search . " %i "))
 org-occur-hook '(org-first-headline-recenter)
 org-agenda-start-with-log-mode t
 org-footnote-auto-adjust t
 org-odd-levels-only t
 org-clock-out-switch-to-state "WAIT"
 org-structure-template-alist '(("p" . "src python") ("a" . "export ascii") ("c" . "center") ("C" . "comment")
                                ("e" . "example") ("E" . "export") ("h" . "export html") ("l" . "export latex")
                                ("q" . "quote") ("s" . "src") ("v" . "verse"))
 org-cycle-hook '(org-cycle-hide-archived-subtrees org-cycle-hide-drawers org-cycle-show-empty-lines
                  org-optimize-window-after-visibility-change)
 org-todo-keywords '((sequence "NONE" "HELP" "WAIT" "ACTV" "|" "CONT" "DONE" "DEAD" "PASS"))
 org-speed-command-hook '(org-speed-command-activate org-babel-speed-command-activate)
 org-roam-node-annotation-function 'org-roam-node-read--annotation
 org-tags-column -100
 org-habit-graph-column 70
 org-roam-ref-annotation-function 'org-roam-ref-read--annotation
 org-roam-dailies-directory "diary/"
 org-babel-tangle-lang-exts '(("python" . "py") ("emacs-lisp" . "el") ("elisp" . "el"))
 org-refile-use-outline-path t
 org-export-before-parsing-hook '(org-attach-expand-links)
 org-confirm-shell-link-function 'yes-or-no-p
 org-link-parameters '(("attachment" :follow org-attach-follow :complete org-attach-complete-link)
                       ("message" :follow org-mac-message-open)
                       ("x-devonthink-item" :follow org-devonthink-item-open)
                       ("mac-evernote" :follow org-mac-evernote-note-open)
                       ("mac-outlook" :follow org-mac-outlook-message-open)
                       ("acrobat" :follow org-mac-acrobat-open) ("skim" :follow org-mac-skim-open)
                       ("addressbook" :follow org-mac-addressbook-item-open)
                       ("x-together-item" :follow org-mac-together-item-open)
                       ("mairix" :follow org-mairix-open :store org-mairix-store-gnus-link)
                       ("roam" :follow org-roam-link-follow-link) ("id" :follow org-id-open)
                       ("eww" :follow org-eww-open :store org-eww-store-link)
                       ("rmail" :follow org-rmail-open :store org-rmail-store-link)
                       ("mhe" :follow org-mhe-open :store org-mhe-store-link)
                       ("irc" :follow org-irc-visit :store org-irc-store-link :export org-irc-export)
                       ("info" :follow org-info-open :export org-info-export :store org-info-store-link)
                       ("gnus" :follow org-gnus-open :store org-gnus-store-link)
                       ("docview" :follow org-docview-open :export org-docview-export :store
                        org-docview-store-link)
                       ("bibtex" :follow org-bibtex-open :store org-bibtex-store-link)
                       ("bbdb" :follow org-bbdb-open :export org-bbdb-export :complete org-bbdb-complete-link
                        :store org-bbdb-store-link)
                       ("w3m" :store org-w3m-store-link) ("file+sys") ("file+emacs")
                       ("shell" :follow org-link--open-shell)
                       ("news" :follow
                        #[514 "\301\300\302 Q \"\207" ["news" browse-url ":"] 6 "\n\n(fn URL ARG)"])
                       ("mailto" :follow
                        #[514 "\301\300\302 Q \"\207" ["mailto" browse-url ":"] 6 "\n\n(fn URL ARG)"])
                       ("https" :follow
                        #[514 "\301\300\302 Q \"\207" ["https" browse-url ":"] 6 "\n\n(fn URL ARG)"])
                       ("http" :follow
                        #[514 "\301\300\302 Q \"\207" ["http" browse-url ":"] 6 "\n\n(fn URL ARG)"])
                       ("ftp" :follow
                        #[514 "\301\300\302 Q \"\207" ["ftp" browse-url ":"] 6 "\n\n(fn URL ARG)"])
                       ("help" :follow org-link--open-help) ("file" :complete org-link-complete-file)
                       ("elisp" :follow org-link--open-elisp) ("doi" :follow org-link--open-doi))
 org-agenda-skip-scheduled-if-done t
 org-latex-format-headline-function 'org-latex-format-headline-default-function
 org-expiry-inactive-timestamps t
 org-capture-templates '(("t" "Task" entry (file+headline "~/mise/TODO" "Schedule Me")
                          "*** NONE %^{Summary}\n    /Captured %U/\n    %?\n")
                         ("s" "Snippet" plain (file+olp+datetree "~/mise/TODO" "Snippets") "        * %?"
                          :empty-lines-after 1 :tree-type week)
                         ("j" "Journal" plain (file+olp+datetree "~/mise/NOTES") "      %?" :empty-lines-before 1
                          :empty-lines-after 1)
                         ("n" "Note" entry (file+headline "~/mise/NOTES" "Notes")
                          "*** %^{Topic}\n    /Captured %U/\n    %?\n" :empty-lines-before 1 :empty-lines-after 1
                          :prepend t)
                         )
 org-link-elisp-confirm-function 'yes-or-no-p
 org-todo-keyword-faces '(("UNINIT'D" . org-todo-uninited) ("NEEDHELP" . org-todo-needhelp)
                          ("BUFFERED" . org-todo-buffered) ("PROGRESS" . org-todo-progress)
                          ("CONTINUE" . org-todo-continue) ("COMPLETE" . org-todo-complete)
                          ("OBSOLETE" . org-todo-obsolete) ("DELEGATE" . org-todo-delegate)
                          ("NONE" . org-todo-uninited) ("HELP" . org-todo-needhelp) ("WAIT" . org-todo-buffered)
                          ("ACTV" . org-todo-progress) ("CONT" . org-todo-continue) ("DONE" . org-todo-complete)
                          ("DEAD" . org-todo-obsolete) ("PASS" . org-todo-delegate))
 org-roam-db-autosync-mode t
 org-roam-dailies-capture-templates '(("d" "default" entry "* %U\n  %?" :target
                                       (file+head "%<%Y-%m-%d-%a>.org"
                                        "#+title: %<%Y-%m-%d> (%<%a>)\n#+filetags: diary\n\n")
                                       )
                                      )
 org-latex-format-inlinetask-function 'org-latex-format-inlinetask-default-function
 org-html-format-drawer-function #[514 "\207" [] 3 "\n\n(fn NAME CONTENTS)"]
 org-roam-directory "/Users/charlestam/mise/roam"
 org-clock-in-switch-to-state "ACTV"
 org-html-format-headline-function 'org-html-format-headline-default-function
 org-mairix-display-hook 'org-mairix-gnus-display-results
 org-pretty-entities-include-sub-superscripts nil
 org-habit-show-all-today t
 org-confirm-babel-evaluate nil
 org-roam-node-display-template "${title:*} ${tags:20}"
 org-agenda-sorting-strategy '((agenda habit-down time-up priority-down effort-up category-keep)
                               (todo scheduled-up) (tags time-up) (search alpha-up))
 org-tags-exclude-from-inheritance '("todo")
 org-agenda-skip-deadline-if-done t
 org-mairix-gnus-select-display-group-function 'org-mairix-gnus-select-display-group-function-gg
 )