diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -13,6 +13,10 @@
 Internal/api/developer-ish changes in the hledger-lib (and hledger) packages.
 For user-visible changes, see the hledger package changelog.
 
+# 1.32.1 2023-12-07
+
+- readFileStrictly is now provided by Hledger.Utils.IO
+
 # 1.32 2023-12-01
 
 Misc. changes
diff --git a/Hledger/Data/Balancing.hs b/Hledger/Data/Balancing.hs
--- a/Hledger/Data/Balancing.hs
+++ b/Hledger/Data/Balancing.hs
@@ -664,7 +664,6 @@
         -- "display precision:  %d",
         "this balance was asserted:     %s", -- (at display precision: %s)",
         "but the calculated balance is: %s", -- (at display precision: %s)",
-        "a difference of:               %s",
         "",
         "To troubleshoot, you can view this account's running balance. Eg:",
         "",
@@ -680,7 +679,7 @@
       -- (showAmount assertedamt)
       (show $ aquantity actualbalincomm)
       -- (showAmount actualbalincommodity)
-      (show $ aquantity assertedamt - aquantity actualbalincomm)
+      -- (show $ aquantity assertedamt - aquantity actualbalincomm)
       (acct ++ if isinclusive then "" else "$")
       (if istotal then "" else (" cur:" ++ quoteForCommandLine (T.unpack assertedcomm)))
       where
diff --git a/Hledger/Data/JournalChecks.hs b/Hledger/Data/JournalChecks.hs
--- a/Hledger/Data/JournalChecks.hs
+++ b/Hledger/Data/JournalChecks.hs
@@ -186,7 +186,7 @@
                     -- where
                     --   col  = T.length (showTransactionLineFirstPart txn') + 2
                     --   col2 = col + T.length tagname - 1
-    declaredtags = journalTagsDeclared j
+    declaredtags = journalTagsDeclared j ++ builtinTags
     msg = (unlines [
       "%s:%d:"
       ,"%s"
@@ -196,6 +196,19 @@
       ,""
       ,"tag %s"
       ])
+
+-- | Tag names which have special significance to hledger.
+builtinTags = [
+   "type"  -- declares an account's type
+  ,"t"     -- generated by timedot letters notation
+  -- optionally generated on periodic transactions and auto postings
+  ,"generated-transaction"
+  ,"generated-posting"
+  -- used internally, not shown (but queryable)
+  ,"_generated-transaction"
+  ,"_generated-posting"
+  ,"_conversion-matched"
+  ]
 
 -- | In each tranaction, check that any conversion postings occur in adjacent pairs.
 journalCheckPairedConversionPostings :: Journal -> Either String ()
diff --git a/Hledger/Read.hs b/Hledger/Read.hs
--- a/Hledger/Read.hs
+++ b/Hledger/Read.hs
@@ -109,6 +109,7 @@
   -- * Misc
   journalStrictChecks,
   saveLatestDates,
+  saveLatestDatesForFiles,
 
   -- * Re-exported
   JournalReader.tmpostingrulep,
@@ -132,7 +133,7 @@
 import Data.Foldable (asum)
 import Data.List (group, sort, sortBy)
 import Data.List.NonEmpty (nonEmpty)
-import Data.Maybe (fromMaybe)
+import Data.Maybe (catMaybes, fromMaybe)
 import Data.Ord (comparing)
 import Data.Semigroup (sconcat)
 import Data.Text (Text)
@@ -243,15 +244,17 @@
 --
 readJournalFile :: InputOpts -> PrefixedFilePath -> ExceptT String IO Journal
 readJournalFile iopts@InputOpts{new_, new_save_} prefixedfile = do
-  (j,latestdates) <- readJournalFileAndLatestDates iopts prefixedfile
+  (j, mlatestdates) <- readJournalFileAndLatestDates iopts prefixedfile
   when (new_ && new_save_) $ liftIO $
-    saveLatestDates latestdates (snd $ splitReaderPrefix prefixedfile)
+    case mlatestdates of
+      Nothing                        -> return ()
+      Just (LatestDatesForFile f ds) -> saveLatestDates ds f
   return j
 
--- The implementation of readJournalFile, but with --new, 
--- also returns the latest transaction date(s) read.
--- Used by readJournalFiles, to save those at the end.
-readJournalFileAndLatestDates :: InputOpts -> PrefixedFilePath -> ExceptT String IO (Journal,LatestDates)
+-- The implementation of readJournalFile.
+-- With --new, it also returns the latest transaction date(s) read from each file.
+-- readJournalFiles uses this to update .latest files only after a successful read of all.
+readJournalFileAndLatestDates :: InputOpts -> PrefixedFilePath -> ExceptT String IO (Journal, Maybe LatestDatesForFile)
 readJournalFileAndLatestDates iopts prefixedfile = do
   let
     (mfmt, f) = splitReaderPrefix prefixedfile
@@ -266,9 +269,9 @@
     then do
       ds <- liftIO $ previousLatestDates f
       let (newj, newds) = journalFilterSinceLatestDates ds j
-      return (newj, newds)
+      return (newj, Just $ LatestDatesForFile f newds)
     else
-      return (j, [])
+      return (j, Nothing)
 
 -- | Read a Journal from each specified file path (using @readJournalFile@) 
 -- and combine them into one; or return the first error message.
@@ -285,20 +288,20 @@
 readJournalFiles :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO Journal
 readJournalFiles iopts@InputOpts{strict_,new_,new_save_} prefixedfiles = do
   let iopts' = iopts{strict_=False, new_save_=False}
-  (j,latestdates) <-
+  (j, latestdatesforfiles) <-
     traceOrLogAt 6 ("readJournalFiles: "++show prefixedfiles) $
     readJournalFilesAndLatestDates iopts' prefixedfiles
   when strict_ $ liftEither $ journalStrictChecks j
-  when (new_ && new_save_) $ liftIO $
-    mapM_ (saveLatestDates latestdates . snd . splitReaderPrefix) prefixedfiles
+  when (new_ && new_save_) $ liftIO $ saveLatestDatesForFiles latestdatesforfiles
   return j
 
 -- The implementation of readJournalFiles, but with --new, 
 -- also returns the latest transaction date(s) read in each file.
 -- Used by the import command, to save those at the end.
-readJournalFilesAndLatestDates :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO (Journal,LatestDates)
-readJournalFilesAndLatestDates iopts =
-  fmap (maybe def sconcat . nonEmpty) . mapM (readJournalFileAndLatestDates iopts)
+readJournalFilesAndLatestDates :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO (Journal, [LatestDatesForFile])
+readJournalFilesAndLatestDates iopts pfs = do
+  (js, lastdates) <- unzip <$> mapM (readJournalFileAndLatestDates iopts) pfs
+  return (maybe def sconcat $ nonEmpty js, catMaybes lastdates)
 
 -- | Run the extra -s/--strict checks on a journal,
 -- returning the first error message if any of them fail.
@@ -371,6 +374,9 @@
 -- and how many transactions there were on that date.
 type LatestDates = [Day]
 
+-- The path of an input file, and its current "LatestDates".
+data LatestDatesForFile = LatestDatesForFile FilePath LatestDates
+
 -- | Get all instances of the latest date in an unsorted list of dates.
 -- Ie, if the latest date appears once, return it in a one-element list,
 -- if it appears three times (anywhere), return three of it.
@@ -383,6 +389,10 @@
 saveLatestDates :: LatestDates -> FilePath -> IO ()
 saveLatestDates dates f = T.writeFile (latestDatesFileFor f) $ T.unlines $ map showDate dates
 
+-- | Save each file's latest dates.
+saveLatestDatesForFiles :: [LatestDatesForFile] -> IO ()
+saveLatestDatesForFiles = mapM_ (\(LatestDatesForFile f ds) -> saveLatestDates ds f)
+
 -- | What were the latest transaction dates seen the last time this
 -- journal file was read ? If there were multiple transactions on the
 -- latest date, that number of dates is returned, otherwise just one.
@@ -404,9 +414,6 @@
 latestDatesFileFor f = dir </> ".latest" <.> fname
   where
     (dir, fname) = splitFileName f
-
-readFileStrictly :: FilePath -> IO Text
-readFileStrictly f = readFilePortably f >>= \t -> C.evaluate (T.length t) >> return t
 
 -- | Given zero or more latest dates (all the same, representing the
 -- latest previously seen transaction date, and how many transactions
diff --git a/Hledger/Read/Common.hs b/Hledger/Read/Common.hs
--- a/Hledger/Read/Common.hs
+++ b/Hledger/Read/Common.hs
@@ -105,6 +105,7 @@
   bracketeddatetagsp,
 
   -- ** misc
+  doublequotedtextp,
   noncommenttextp,
   noncommenttext1p,
   singlespacedtext1p,
@@ -657,6 +658,11 @@
 -- for now it remains as-is for backwards compatibility.
 accountnamep :: TextParser m AccountName
 accountnamep = singlespacedtext1p
+
+-- | Parse a single line of possibly empty text enclosed in double quotes.
+doublequotedtextp :: TextParser m Text
+doublequotedtextp = between (char '"') (char '"') $
+  takeWhileP Nothing $ \c -> not $ isNewline c || c == '"'
 
 -- | Parse possibly empty text, including whitespace, 
 -- until a comment start (semicolon) or newline.
diff --git a/Hledger/Read/JournalReader.hs b/Hledger/Read/JournalReader.hs
--- a/Hledger/Read/JournalReader.hs
+++ b/Hledger/Read/JournalReader.hs
@@ -629,7 +629,7 @@
 payeedirectivep = do
   string "payee" <?> "payee directive"
   lift skipNonNewlineSpaces1
-  payee <- lift $ T.strip <$> noncommenttext1p
+  payee <- lift $ T.strip <$> (try doublequotedtextp <|> noncommenttext1p)
   (comment, tags) <- lift transactioncommentp
   skipMany indentedlinep
   addPayeeDeclaration (payee, comment, tags)
@@ -1134,8 +1134,10 @@
       }
 
   ,testGroup "payeedirectivep" [
-       testCase "simple"             $ assertParse payeedirectivep "payee foo\n"
+        testCase "simple"             $ assertParse payeedirectivep "payee foo\n"
        ,testCase "with-comment"       $ assertParse payeedirectivep "payee foo ; comment\n"
+       ,testCase "double-quoted"      $ assertParse payeedirectivep "payee \"a b\"\n"
+       ,testCase "empty        "      $ assertParse payeedirectivep "payee \"\"\n"
        ]
 
   ,testCase "tagdirectivep" $ do
diff --git a/Hledger/Utils/IO.hs b/Hledger/Utils/IO.hs
--- a/Hledger/Utils/IO.hs
+++ b/Hledger/Utils/IO.hs
@@ -9,7 +9,7 @@
 
 -}
 
-{-# LANGUAGE CPP, LambdaCase #-}
+{-# LANGUAGE CPP, LambdaCase, PackageImports #-}
 
 module Hledger.Utils.IO (
 
@@ -80,6 +80,7 @@
   expandGlob,
   sortByModTime,
   readFileOrStdinPortably,
+  readFileStrictly,
   readFilePortably,
   readHandlePortably,
   -- hereFileRelative,
@@ -91,6 +92,7 @@
   )
 where
 
+import qualified Control.Exception as C (evaluate)
 import           Control.Monad (when, forM)
 import           Data.Colour.RGBSpace (RGB(RGB))
 import           Data.Colour.RGBSpace.HSL (lightness)
@@ -125,7 +127,7 @@
   defaultOutputOptionsDarkBg, defaultOutputOptionsNoColor, pShowOpt, pPrintOpt)
 
 import Hledger.Utils.Text (WideBuilder(WideBuilder))
-import System.FilePath.Glob (glob)
+import "Glob" System.FilePath.Glob (glob)
 import Data.Functor ((<&>))
 
 -- Pretty showing/printing with pretty-simple
@@ -460,6 +462,10 @@
 sortByModTime fs = do
   ftimes <- forM fs $ \f -> do {t <- getModificationTime f; return (t,f)}
   return $ map snd $ reverse $ sort ftimes
+
+-- | Like readFilePortably, but read all of the file before proceeding.
+readFileStrictly :: FilePath -> IO T.Text
+readFileStrictly f = readFilePortably f >>= \t -> C.evaluate (T.length t) >> return t
 
 -- | Read text from a file,
 -- converting any \r\n line endings to \n,,
diff --git a/hledger-lib.cabal b/hledger-lib.cabal
--- a/hledger-lib.cabal
+++ b/hledger-lib.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hledger-lib
-version:        1.32
+version:        1.32.1
 synopsis:       A library providing the core functionality of hledger
 description:    This library contains hledger's core functionality.
                 It is used by most hledger* packages so that they support the same
