English
Action Pipeline Performance
The evaluation basis of the Emaki action pipeline is as follows: architecturally provable advantages, a reproducible benchmark method, and the results table. This environment has no Paper/Folia server, so every quantified cell is marked "not run" with a closing condition — architecture claims are backed by source code, while numbers must be measured on a real server before they may be cited externally
Architectural advantages (source-verifiable)
1. Compiled once, zero parsing at runtime
A pipeline is compiled exactly once at config load through PipelineParser + StaticValidator into a CompiledPipeline (AST + type-checked arguments). At runtime ActionInterpreter executes that structure directly:
- no re-tokenization, no argument type checks, no unknown-stage lookups;
- argument rendering only runs
renderfor values containing placeholders; pure literals are skipped; - compile failures are reported in full at load time (48+ rules), so a wrong stage name never surfaces only at execution
2. Gate short-circuiting and domain grouping
- Gate short-circuit: a source returning
Emptyor a gate returningHaltedenters a terminal state (stopped) immediately; all later stages are skipped with no cross-domain dispatch - Same-domain batching:
StageGroupfolds consecutive same-domain stages into one dispatch (foldablestages attach to the previous group), reducing Paper/Folia thread hops — e.g. twoCONTEXT_ENTITYstages ("edit inventory" + "set XP") cause a single owner-thread transfer - Five-domain classification:
SERVER_GLOBAL/CONTEXT_ENTITY/LOCATION_REGION/ASYNC_COMPUTE/UNDECLAREDare mandatory at registration (StageRegistry.checkDomain);StageDispatcherroutes by domain at runtime. Competitors generally have no domain classification, which is Emaki's structural difference on Folia
3. Zero-allocation observation on hot paths
The default StepReporter is NOOP (empty interface methods), so in non-debug runs every observation point is an empty call; ActionAuditLogger returns early when there is no DebugLogger. The observation layer adds no allocation or branch cost to production hot paths
4. Elimination before execution
Every gate's in/out counts are reported on StepReporter.gate (rendered as a funnel in dry-run/debug mode); the semantics are elimination before execution — filter/where eliminate unqualified targets before any action runs, avoiding cross-domain dispatches for invalid targets
Benchmark method (reproducible)
Follow the sampling discipline in .spigot-dev/guides/performance-baseline.md: only same-scenario, same-duration, same-scale runs are comparable. Three required scenarios:
| Scenario | Measures | Trigger | Budget |
|---|---|---|---|
| Pipeline throughput | Completed pipeline runs per second | Run a fixed short pipeline (e.g. self | damage amount=1) in execute mode for a 120s spark sample | Fill after a real-server baseline |
| P95 latency | End-to-end latency of one pipeline | Same as above, with method-level sampling of ActionInterpreter.walk | Fill after a real-server baseline |
| Gate short-circuit benefit | Elapsed time of Halted/Empty path vs all-pass path | Compare filter 'health_percent<=0' (always eliminates everything) against filter 'health_percent<=100' (always passes) | Short-circuit path should be significantly cheaper |
Observation commands:
/spark profiler start --timeout 120
# run the fixed scenario...
/spark profiler stop --save-to-fileTo measure grouping benefit, compare StageDispatcher.dispatch call count against dispatched stage count in the spark method profile — with batching active that ratio should be clearly below 1
Quantified results
| Metric | Value | Collected | Status |
|---|---|---|---|
| Pipeline throughput (runs/s) | — | — | not run |
| P95 end-to-end latency | — | — | not run |
| Gate short-circuit benefit (short-circuit vs all-pass) | — | — | not run |
| Dispatches per stage after batching | — | — | not run |
Closing condition: on a Paper 26.1 server, run one spark sample per scenario above, fill the numbers back into this table with a collection date. Until then no quantified cell may be filled with estimated values
Comparison stance against competitors
- Statically citable (source-level facts): five-domain thread grouping with mandatory Folia domain declarations (MythicMobs/Skript have no such mechanism); 48+ compile-time diagnostics (MythicMobs relies on runtime errors + guessing from the Wiki)
- Not citable: any throughput, latency, or TPS number. Competitor figures are marketing claims too; re-check the source date before quoting them externally