I was looking at a flame graph of an ingestion workload with @dliappis, and it looks like we parse the JSON representation of the index request twice when a document has both a pipeline and a final pipeline.

It's hard to know how much we would save on this benchmark since not all data streams in this benchmark had both a pipeline and a final pipeline, but the cost of parsing index request into maps of maps via IngestService represented 4.06% of overall CPU time according to the flame graph, so this might not be negligible.
server/src/main/java/org/elasticsearch/ingest/IngestDocument.java
boolean wasSuccessful;
        String errorMessage;
        Object resolvedObject;
        static ResolveResult success(Object resolvedObject) {
            ResolveResult result = new ResolveResult();
            result.wasSuccessful = true;
            result.resolvedObject = resolvedObject;
            return result;
        }
        static ResolveResult error(String errorMessage) {
            ResolveResult result = new ResolveResult();
            result.wasSuccessful = false;
            result.errorMessage = errorMessage;
            return result;
        }
    }
    /**
     * Provides a shallowly read-only, very limited, map-like view of two maps. The only methods that are implemented are
     * {@link Map#get(Object)} and {@link Map#containsKey(Object)}, everything else throws UnsupportedOperationException.
     *
     * The overrides map has higher priority than the primary map -- values in that map under some key will take priority over values
     * in the primary map under the same key.
     *