v0.3.0
Observability and lifecycle reporting: a host can now say which plugin a
failure came from, order the transitions it observes, account for what it
drops, and size its own shared memory. Plus the teardown and crash-reporting
fixes that writing those answers surfaced.
Full detail in CHANGELOG.md.
Added
- Typed lifecycle verdicts.
EventUnhealthycarries a typed error
(MissedHeartbeatsError,WedgedError) instead of prose, so a consumer can
branch on which check failed rather than matching message text. Sentinels
ErrHeartbeatsMissedandErrWedgedwork witherrors.Is. - Panic identity.
PluginPanicErrornames the plugin, service, and method.
Calls through generated stubs address methods by numeric ID and had no name
to report at all; the generator now registers each method's name via
RegisterIdentityName, resolved only when a panic actually happens, with an
allocation gate holding the ordinary call path to its measured cost.
Regenerate stubs with the v0.3.0 generator to get named panics. - Drop accounting.
observe.MetricStdioDropped,MetricObserveDropped,
andMetricStdioSinkPaniccount stdio lines and observability records a host
discards. Reported as per-interval deltas rather than one event per drop, so
a plugin spraying output cannot turn a counter into its own flood, with a
final delta when an instance ends so the interval a crash cuts short is still
accounted for. - Health transition revisions.
Event.Revisionand
HealthSnapshot.Revisionlet a consumer seed fromHealth()and fold
Events()with one comparison.KindandTimecannot do this: the bus
delivers a criticalEventCrashedahead of an informationalEventStarting
published before it, and two events in the same tick carry equalTime.
Revisions are comparable only within oneEvent.Plugin. ShmGeometry.RegionBytes(). Reports the exact per-plugin region size,
derived by the same code that lays out a real region so the two cannot drift.
Default geometry reserves 65,994,752 bytes per plugin — the number to size a
container against.
Changed
Host.Stophonors its context on every path it previously outran: a
supervisor a parkedStarthad not handed over, pinned-binary hashing under
the host lock, and a worker release owned by another caller. Concurrent
Stopcallers are now linearized. A caller passing a tight deadline will see
context errors where it previously blocked and eventually succeeded —
teardown continues in the background; the error says the wait ended.Host.Startafter aStophas begun reportsErrHostStopped.
Fixed
- A crash's stderr is no longer lost to the sink queue. The tail a crash
reason is built from was reachable only through the same bounded queue that
feeds aPluginSpec.Stdiosink, so a sink falling behind, or the
cancellation that precedes reporting a crash, could empty
PluginCrashError.StderrTailand the stderr suffix insideReason. A plugin
that sprayed output before dying was then indistinguishable from one that
printed nothing. The tail is now written by the goroutine that reads the
pipe, before the queue.
Compatibility
Source-compatible with v0.2.0 except for positional composite literals of
styx.Event and styx.HealthSnapshot, which gained a Revision field. Keyed
literals and reads are unaffected:
grep -rn 'styx\.Event{[^K]' --include='*.go' .
grep -rn 'styx\.HealthSnapshot{[^A-Z]' --include='*.go' .
Pre-1.0: the public Go API may still move between minor versions. The wire
contracts (shm-abi.md, stream-protocol.md) are frozen.
Known gap
A narrower stderr-loss window remains: the stdio pipes are closed during
process teardown while the reader may still be draining them, so a plugin that
writes to stderr and exits in the same instant can still lose its tail. Closing
it needs a bounded join before the close, since a plugin leaking a grandchild
that holds the stderr write end would otherwise hang teardown — a
teardown-ordering change deliberately left out of this release. Where stderr is
the whole diagnosis, configure a PluginSpec.Stdio sink and log from there as
well; that path does not share this window.