SGKEMBEDDED PERFORMANCEEpicTunerSDK · PrereleaseContact ↗
EpicTuner SDK/ SDK 1.0.0-pre.3: actionable diagnostics

Download the complete Markdown manual ↓
One file with guides, API headers and examples for developers and coding agents.

SDK 1.0.0-pre.3: actionable diagnostics

Recommended host: EpicTuner 0.8.5 or later. C ABI 1.1 and all service layouts are unchanged. Existing compiled plugins receive the richer host diagnostics without recompiling. Recompile to use the new C++ source helpers.

Read the actual failure

Tools > Plugins now shows UTC timestamps and INFO/WARN/ERROR labels. Use Copy diagnostics to copy the plugin identity, version, error and retained log. The log is bounded; capture a failure promptly instead of flooding retries.

Host UI rejections include the symbolic result, operation, request ID, panel and instance key, and up to three affected node/property targets. Conflict messages include the submitted and current revision and whether the latest change came from an accepted plugin patch or a user event. Detail is bounded to 512 characters; long identifiers or many targets can be truncated. Patch values are not logged.

Example (illustrative IDs and revisions):

request=42 ui.patch ET_ERROR_CONFLICT(12) panel='org.example.loader.main/': submitted=6 current=7; last change: accepted plugin patch. Use completion.value.u64 after success or the latest event.revision; rebuild after user input, do not retry a stale patch.; targets=[model.options; model.value]

If the last change was accepted plugin patch, a previous successful update advanced the revision. A timer or completion callback must stop reusing the old event revision. If the last change was user event, recompute from that new event; retrying an old model can overwrite a user's newer choice. The last-change description reports the most recent mutation, not a complete revision history.

Log both immediate and asynchronous results

ET_OK returned by ui.patch means queued, not applied. An immediate failure does not schedule a completion. Check both paths. Store Context by value (as the starter does); the start() reference itself is temporary.

static void ET_CALL completed(void* owner, const et_completion* c) noexcept {
    auto& self = *static_cast<MyPlugin*>(owner);
    try {
        self.context->check(*c, "Populate Model/Tune and preview");
        if (c->code == ET_OK && c->value.kind == ET_VALUE_U64) {
            // This callback belongs to one known panel. Never move backwards
            // if a newer event for that same panel has already arrived.
            self.revision = std::max(self.revision, uint32_t(c->value.data.u64));
        }
    } catch (...) { /* Never let exceptions cross the ABI. */ }
}
// On the dispatcher, with a persistent completion owner:
context->check(ui.patch(panel, changes, revision, 0, &completion), "Queue preview");

Context::check(const et_completion&, step) logs failed completions, including request/operation ID, symbolic/numeric result, integer revision when present, and the borrowed detail copied inside the callback. completionMessage(c, step) returns the same string for your own logger. resultName(code) returns a stable symbolic label, including ET_ERROR_UNKNOWN for unknown codes. These are header helpers, not new ABI entry points. Declare the log capability for SDK logging.

For UI patch completions, ET_VALUE_U64 is the panel revision, including on a conflict. Do not treat integer values from other services as UI revisions. Use separate state and completion context for each panel; reset it on close or reopen. A failed patch does not authorize replay against its reported revision.

Avoid repeated conflicts

  • Prefer one atomic patch for related options, selected indexes and preview data.
  • Synchronous patches inside one event are sequenced by host 0.8.4+ (including default origin 0). This does not extend to later timers or job completions.
  • For deferred updates, allow one in-flight patch per panel, retain the latest event and completion revisions, and coalesce newer display state while waiting.
  • On conflict, report it once and wait for/recompute from fresh state. Do not increment a guessed revision or repeatedly resubmit the same patch.
  • A failed event-chain predecessor cancels its dependent patches. The cancellation names the predecessor request and preserves its error context.
  • Immediate limit diagnostics report pending/rate budgets; reduce update volume. A timeout reports the request, operation and timeout before stopping the worker.

The starter and cascading-select examples demonstrate completion logging. See UI contracts and troubleshooting for lifecycle, dispatcher, ownership and validation rules.