# Processes, callbacks and ownership

An EpicTuner plugin is a native library loaded into its own worker process.
The application owns ECU communication, calibration validation, licensing and
the panels rendered with EpicTuner controls.

## The path of a request

```text
Your C++ plugin
    ↓ C++ helpers / C ABI service tables
Plugin worker (one process per enabled plugin)
    ↓ bounded authenticated local messages
EpicTuner broker
    ↓ GUI models, read adapters, edit validation, settings and licensing
Application and its existing ECU communication worker
```

The function pointers and C++ objects remain inside the worker. IPC carries
bounded values and IDs, never pointers or raw C structure images. Each panel
from a plugin shares that plugin's worker. Worker process separation contains
crashes; it is not an OS security sandbox. A native library still has the current
user account's file and network access.

## Lifecycle

The host discovers and verifies a package, checks compatibility, then starts an
enabled plugin. The worker negotiates `et_plugin_query` and calls `start`.
Lifecycle, UI and read callbacks are serialized on its dispatcher. A plugin that
starts successfully becomes ready.

Disable, update and exit drain or cancel owned work before `stop` destroys the
instance. The host replaces the worker process for updates. It does not unload a
library with live callbacks. A crash or missed heartbeat changes the plugin to a
visible failure state, revokes subscriptions and disables its controls.
Restart is explicit; it never replays prior actions or tune writes.

## Threading

Call host services from the worker dispatcher. Use [jobs](JOBS.md) for expensive
CPU work. A job receives copied inputs and a cancellation token, computes a
bounded result, and returns through a dispatcher completion. Do not call UI,
logging or read services from the job thread.

Never block a callback waiting for a dialog, request or job to finish. Deliver
the next step from its completion callback. The application GUI never waits
synchronously for plugin code.

## Data lifetimes

| Value | Lifetime |
|---|---|
| Request strings, nodes, channel arrays | Copied during the service call |
| Event/reply strings and arrays | Borrowed until the callback returns |
| Callback owner | Must remain alive until cancellation/completion has drained |
| Panel/subscription/proposal handle | Scoped to its worker session and relevant project generation |
| C++ object or allocation | Created and destroyed in its own module |

Copy a borrowed log batch before passing it to a background task. Treat handles
as opaque tokens. A project close or replacement invalidates generation-bound
work even if the newly opened project has the same name or path.

## Error handling

Service calls can fail immediately without queuing a callback. Otherwise the
terminal callback reports success, cancellation or rejection. A timeout does
not prove that a calibration commit failed; consult host status and read back
the current tune before proposing another edit.

The C++ adapters catch callback exceptions inside the module and translate them
to `ET_ERROR_CALLBACK`. C authors must provide the same no-exception boundary.
See [foundation](FOUNDATION.md), [API reference](API_REFERENCE.md) and
[troubleshooting](TROUBLESHOOTING.md) for exact contracts.
