I've made some progress. The problem turned out to be with (a) limitations of the -exportArchive command and (b) Xcode's new workflow for notarization.
It appears that the command-line equivelent of generating an archive of your project, uploading it for notarization, and finally producing the finished (stapled) app package is thus:
xcodebuild \
-workspace MyApp.xcworkspace \
-scheme MyScheme \
-configuration Release \
-archivePath $Release/MyApp.xcarchive \
archive
xcodebuild \
-exportArchive \
-archivePath $Release/MyApp.xcarchive \
-exportOptionsPlist ExportOptions.plist
That performs the archive and uploads the app for notarization. The ExportOptions file will need to look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>destination</key>
<string>upload</string>
<key>method</key>
<string>developer-id</string>
<key>signingStyle</key>
<string>automatic</string>
<key>teamID</key>
<string>Your team id</string>
</dict>
</plist>
Note that in my project, the product is already signed so signingStyle and teamID are unnecessary.
Finally, once the notarization service is finished you can export that stapled app:
xcodebuild \
-exportNotarizedApp \
-archivePath $Release/MyApp.xcarchive \
-exportPath $Release/MyAppDistribution
This last step still isn't working for me, because even after I receive notification that the app has been notarized and is ready for release, the xcodebuild -exportNotarizedApp comand just reports "Ticket not found" errors.
Finally, the other stumbling block I was encountering is that all of this depends on exporting and uploading a *single* app for notarization. The export/upload will fail if there is more than one product in the archive. Our top-level build target produces all three apps that get distributed to our users.
So I had to refactor our build so that each app gets archived, uploaded, notarized, and exported individually.