diff --git a/dataframe-arrow.cabal b/dataframe-arrow.cabal
--- a/dataframe-arrow.cabal
+++ b/dataframe-arrow.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               dataframe-arrow
-version:            1.0.3.0
+version:            1.0.3.1
 synopsis: Arrow C Data Interface foreign library for the dataframe Python bindings.
 
 description: Native-shared library exposing the dataframe lazy executor to
@@ -57,9 +57,9 @@
     other-modules:    DataFrame.FFI
     build-depends:
         base                  >= 4   && < 5,
-        dataframe-core ^>= 2.5,
-        dataframe-learn ^>= 2.4.2,
-        dataframe-arrow-bridge ^>= 1.0,
+        dataframe-core ^>= 2.7,
+        dataframe-learn ^>= 2.5,
+        dataframe-arrow-bridge ^>= 1.1,
         dataframe-fastcsv     ^>= 1.4.0.1,
         text                  >= 2.1 && < 3,
         aeson                 >= 0.11 && < 3,
diff --git a/ffi-export/DataFrame/FFI.hs b/ffi-export/DataFrame/FFI.hs
--- a/ffi-export/DataFrame/FFI.hs
+++ b/ffi-export/DataFrame/FFI.hs
@@ -55,10 +55,7 @@
 foreign export ccall "dfExecutePlan"
     dfExecutePlan :: CString -> Ptr Word64 -> Ptr Word64 -> IO CInt
 
-{- | Execute a JSON-encoded query plan, returning Arrow C Data Interface
-pointers to Python via the @schemaOut@/@arrayOut@ output parameters (each an
-address as a 'Word64'). Returns 0 on success, -1 on error.
--}
+-- | Run a JSON query plan and return Arrow C Data Interface pointers.
 dfExecutePlan :: CString -> Ptr Word64 -> Ptr Word64 -> IO CInt
 dfExecutePlan planCS schemaOut arrayOut = do
     planBytes <- BS.packCString planCS
@@ -89,10 +86,7 @@
 foreign export ccall "dfFreeModel"
     dfFreeModel :: Ptr CChar -> IO ()
 
-{- | Fit a TAO decision tree on a plan's materialized result, predicting the
-target column from the rest (@target_type@: @"auto"@ or a wire type tag;
-@config_json@: 'TreeConfig' fields). Caller frees via 'dfFreeModel'; 0 ok, -1 err.
--}
+-- | Fit a TAO decision tree on a plan's result; caller frees via 'dfFreeModel'.
 dfFitDecisionTree ::
     CString ->
     CString ->
@@ -179,7 +173,7 @@
 
 treeConfigFromJson :: TreeConfigJson -> TreeConfig
 treeConfigFromJson j =
-    TreeConfig
+    defaultTreeConfig
         { maxTreeDepth = pick jcMaxDepth maxTreeDepth
         , minSamplesSplit = pick jcMinSamplesSplit minSamplesSplit
         , minLeafSize = pick jcMinLeafSize minLeafSize
@@ -189,7 +183,7 @@
         , taoConvergenceTol = pick jcTaoConvergenceTol taoConvergenceTol
         , columnOrdering = defaultColumnOrdering
         , synthConfig =
-            SynthConfig
+            defaultSynthConfig
                 { maxExprDepth = pickS jcMaxExprDepth maxExprDepth
                 , boolExpansion = pickS jcBoolExpansion boolExpansion
                 , disallowedCombinations = []
@@ -205,9 +199,7 @@
     pickS :: (TreeConfigJson -> Maybe a) -> (SynthConfig -> a) -> a
     pickS getter dflt = Data.Maybe.fromMaybe (dflt defaultSynthConfig) (getter j)
 
-{- | Need this so we don't specify types on the Python side
-but it means out type universe is limited/falls back to string.
--}
+-- | Infer the target wire type, falling back to string.
 inferTargetType :: T.Text -> DataFrame -> T.Text
 inferTargetType target df = dispatchType (columnTypeRep (unsafeGetColumn target df))
   where
