## Contributor description — original implementation
The contributor’s original description follows. Historical heads, scope and open decisions in this section refer to that implementation; the reviewed current implementation, compatibility decision and proof are recorded in the maintainer update below.
Closes#133245.
Related: #127950. This supersedes the current-main-incompatible queue-owned approach in #125385 while preserving today's canonical timeout retry disposition.
## What Problem This Solves
A durably claimed channel message can wait behind another follow-up turn for longer than the five-minute claim-to-adoption watchdog. Existing liveness renewal covers queue-head active-run admission checks, but not an ingress-backed lifecycle waiting deeper in the follow-up queue. The claim can therefore be retired before the message reaches the model.
## Why This Change Was Made
The follow-up queue now owns periodic deferred heartbeats for the exact ingress lifecycle while it remains in pending items, in-flight delivery, summary sources, or compacted summary elisions.
Ingress supplies a cadence derived from one third of its adoption-stall timeout. Debounce, Plugin SDK fan-in, and channel lifecycle wrappers preserve the shortest applicable cadence. Queue ownership triggers an immediate renewal, then periodic renewal; it stops after successful adoption, completion, ownership loss, or callback failure. A rejected adoption callback keeps renewal alive for the supported retry path.
The existing watchdog and canonical timeout retry policy remain unchanged, so silent handlers and orphaned claims still recover normally.
## User Impact
Messages accepted by durable channel ingress remain adoptable while they wait behind long-running work instead of silently disappearing before model execution. No setting or migration is required.
## Evidence
SDK documentation polish (2026-09-10, head `76097fef9397a04c10637e06dfaf64ebb6ca104a`): the public channel SDK guide now documents forwarding both heartbeat fields, the shortest-positive-finite fan-in cadence, renewal termination, and compatibility when older wrappers omit the optional cadence. The documentation-only addition passed changed-page formatting, MDX sanity, and `git diff --check`; production code and the previously tested runtime head below are unchanged. Current-head hosted CI has completed successfully; the final exact-head ClawSweeper review accepts the implementation and proof, leaving only SDK-owner acceptance of the documented contract.
Refreshed on 2026-09-08 for exact head `57c4faff0ed7bb2d9b4fd308aa46b19ae4095e61`, rebased onto `1ff45cad5a`.
- Preserved upstream's ingress-monitor type extraction and gateway-suspension repair; the optional cadence field follows its new type owner.
- Repaired the retry integration fixture: after real enqueue and initial renewal, only the abandoned message's heartbeat callback fails. The real watchdog then recovers it. Retry delivery, healthy sibling cleanup, and true duplicate assertions remain intact; no production behavior or timeout changed for this repair.
- 102 focused tests pass: dispatch ingress retry, queue in-flight/dedupe, ingress lifecycle/watchdog, Plugin SDK fan-in, Discord queue handling, and Slack handler.
- Changed-file gates pass: core/core-test/extension typechecks, formatting, changed core/extension lint, SDK boundaries/exports, dead-export scans, and repository guards.
- Fresh independent source review found no actionable P0–P2 defects. The standalone autoreview CLI failed at startup without a verdict and is not counted as review coverage.
- Current-head CI run [34520397963](https://github.com/openclaw/openclaw/actions/runs/34520397963) completed successfully. The earlier startup subprocess timeout is historical, not a current failing gate. Exact-head ClawSweeper review (September 10, 20:00 UTC) reports no actionable correctness or proof findings; explicit SDK-owner acceptance remains required before merge.
- Existing regressions cover immediate renewal after late handoff, periodic deeper-queue renewal, stopping after owner loss, and continuing across a rejected adoption callback.
Exact-head durable-ingress boundary proof used isolated SQLite with the production ingress drain/lifecycle binder, follow-up queue, and canonical adoption helper. The model callback was synthetic; this is not live Telegram or Discord transport proof. No production Gateway, channel state, or configuration was touched. Temporary state and queue ownership were cleaned up.
```json
{
"schema": "openclaw.pr133248.durable-ingress-proof.v1",
"exactHead": "57c4faff0ed7bb2d9b4fd308aa46b19ae4095e61",
"setup": {
"durableStore": "isolated OpenClaw SQLite state",
"executor": "production follow-up queue with synthetic model callback",
"transportLifecycle": "production ingress drain lifecycle",
"adoptionStallTimeoutMs": 180
},
"queuedBehindLongTurn": {
"heldMs": 620,
"formerDeadlineCrossed": true,
"heartbeatCount": 11,
"claimStillOwnedAtCheckpoint": [
"queued-event"
],
"retryRowsAtCheckpoint": 0,
"failedRowsAtCheckpoint": 0,
"executionCount": 1,
"duplicateAfterAdoption": "completed"
},
"orphanRecovery": {
"status": "released-for-retry",
"attempts": 1,
"lastErrorContainsHandlerTimeout": true
},
"productionTouched": false
}
```
Owner acceptance:
- Intended behavior: accepted messages remain adoptable while their exact lifecycle is owned by the queue; ownerless claims retain canonical timeout recovery.
- Boundary: one optional cadence field propagated through existing shared lifecycle and channel wrappers; no configuration, schema, or migration change.
- Maintainer decision remains open: accept the additive public Plugin SDK lifecycle field and its queue-owned cadence semantics. Bot review is not that acceptance.
- Rollback: revert the renewal fix and its companion retry-fixture adjustment.
- Scope: 23 files, +273/-2. The width is required lifecycle forwarding; renewal policy stays in the queue and ingress drain.
AI-assisted.
---
## Maintainer update — reviewed head `9325ad501aa4`
## What Problem This Solves
Messages accepted while a long reply is running can expire in the follow-up queue and consume a retry. The reproduction confirmed expiry and retry; all three messages eventually arrived. It did not reproduce the older permanent-loss report in #133245.
## Fix and impact
The queue starts one heartbeat when it accepts a lifecycle and stops it on adoption, completion, cancellation, or callback failure. Heartbeats no longer scan queue collections or copy the in-flight set. Ingress remains responsible for the watchdog and retry settlement, and a heartbeat cannot undo the watchdog pause during adoption finalization.
Ingress derives the cadence from its adoption timeout. The optional lifecycle metadata remains necessary because wrappers rebuild callbacks and combine abort signals, losing the original timeout. No channel setting, schema, migration, dependency, or protocol change is added.
The simplification removes 110 lines net from the initial implementation plus main merge. Total production growth is 40 lines. Existing lifecycle types are reused, and the queue cases share the existing lifecycle test fixtures.
## Evidence
- Real Gateway and Discord: three marked messages on one route, with a queued reply held for 330 seconds. Main expired the third claim after 300.004 seconds. This head retained the same claim at 322.257 seconds with zero attempts; replies arrived once, in order, at 17.804, 349.201, and 350.223 seconds.
- Real SQLite/drain/binder/queue controls: explicit abandonment releases the claim; callback failure stops renewal and lets the watchdog retry without model execution.
- 191 core owner/sibling tests and 190 channel tests passed. All five new regression cases failed on plain main for the intended reasons.
- The local preflight passed core/extension type-aware lint, production and test types, script types, and protocol checks in an isolated checkout of this head.
- External consumers compiled and ran against published 2026.9.4 and this head, including omitted metadata, forwarding, optional return fields, and asynchronous abandonment.
## Consumers
Shared ingress binding, batching, reply dispatch, and the Feishu, Slack, Telegram, and Twitch wrappers preserve the source cadence. The fan-in uses the shortest valid cadence. Legacy wrappers that omit the optional field retain their existing head-only heartbeat behavior. Adoption, queue clearing, overflow, cancellation, summaries, and drain replacement retain or finish the same lifecycle owner.
Closes#133245.
Original implementation and report by @PollyBot13 (#133245). The contributor's commits and authorship are retained.
AI-assisted.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
Keep API, endpoint, and request override facts tied to the selected configured model. Reuse the existing configured-row resolver and remove duplicate prefix stripping and normalized-row merging from harness support.
Preserve literal legacy selection, legacy-only fallback, and same-spelling duplicate semantics. Registered-harness regressions fail in both conflicting row orders before the fix; 203 focused tests, the changed-file gate, and independent review pass.
Related: #130706, #143822.
* fix(tasks): settle orphaned execution records at restore
Record nullable process ownership for Gateway runs and local native harness
processes. Settle confirmed dead owners through the existing restart outcome
normalizer before restored tasks can block another drain. Preserve live,
foreign-host, unknown, and legacy ownership.
Add compatible nullable SQLite columns without changing the schema version.
Reported by @gregbond (#143420).
* fix(tasks): keep unchanged restores read-only
Request write admission only when restored state contains a confirmed orphan,
then reread and revalidate ownership before persisting settlement. Preserve
existing create/delete admission-failure semantics and cover a concurrent
owner rebind.
List the three approved nullable ownership columns in the canonical additive
schema contract test without relaxing its declaration checks.
* fix(tasks): preserve newer flow results during restore
Synchronize a restored orphan's mirrored flow only when that task is the
latest linked record. Keep newer live and completed successors' status,
goal, and terminal timestamps while still settling the orphaned task.
Cover both mixed-owner cases through the registry restore boundary.
Isolate the native hook relay build graph while preserving readonly state lookup, explicit policy decisions, and the lazy authenticated Gateway fallback.
Cancel disconnected request waits through the existing approval authority. Keep duplicate callers independently cancellable, retain unbound durable approval deduplication, and detach exact relay-owned entries before callbacks so old cleanup cannot remove a successor. Observe already-started promises when synchronous cancellation wins.
Update managed Codex to the official 0.154.0 release and align its version fixtures and current documentation. This improves lifecycle ownership and reduces the relay import closure; it does not cap hook concurrency, prove faster bursts, or establish resolution of the historical constrained-host timeout.
Related: https://github.com/openclaw/openclaw/issues/91009
Thanks to @nvtoroy for the constrained-host captures and guarded opt-out evidence in https://github.com/openclaw/openclaw/pull/121668 and https://github.com/openclaw/openclaw/pull/111205. The opt-out proposal remains distinct and unimplemented by this change.
Keep setup choices on the canonical manifest/install-catalog flow and remove
the unused runtime option producer, private shape, and builder. Retain
provider choice resolution, model pickers, model-selected hooks, and public
provider types. Move repository-local test coverage to the surviving owners
and remove only the already-retired test-helper exports and documentation.
Include the canonical constrained-host lint prerequisite from
9229af2c9e (#146186), authored by
Peter Steinberger <steipete@gmail.com>. Its three files are preserved
byte-for-byte. This prerequisite is already upstream and is not counted
as cleanup production savings.
Validation: 57 focused functional cases, 76 lint-runner cases, and all 42
combined changed checks passed. The normal Linux gate selected five core
lint batches on the reported 4-CPU/15-GiB runner. A two-pass precommit
review found no P0-P2 issues. Prior diagnostic failures remain retained;
no full package-build or new peak-memory measurement is claimed.
* feat: give every plugin a compact chat activity icon
Separate package-owned activity SVGs from plugin identity artwork. Ship 154 defaults and seven exact tool overrides, preserving Echo and the progress claw. Include authenticated bounded delivery, safe mask rendering, packaging, and authoring guidance.
* test: declare Vite types for the activity asset browser test
* refactor: keep plugin artwork selection with catalog presentation facts
* test: scope activity browser types and simplify fixture copies
* feat: load CDN libraries and fonts in widgets
Share public static-resource origins across document, sandbox, and channel policies while keeping API access and native Gateway pins separate. Add visualization guidance for inline code explanations and persistent dashboards.
* fix: preserve local widget renderers in direct hosting
Keep document-approved same-origin renderer scripts available in the intersecting HTTP CSP. Cover stored and newly wrapped registered documents without granting API connections.
Keep plugin view selection and reload on the Plugins page. Render that page in the built-in workspace so operators can recover custom workspaces without a floating control.
* refactor(workboard): run SQLite persistence in workers
Preserve board-scoped hydration and card-scoped notification reads while moving complete database operations to plugin-owned worker connection leases. Drain admitted work and retain retryable cleanup across service retirement and transport failure.
* test(workboard): preserve unclassified plugin routing coverage
* test(workboard): await persisted cleanup outcomes
Route artifact and attendance summaries through the existing output writer, preserving summary bytes, file modes, and explicit write failures. Remove the direct-stdout summary paths.
Keep inbound channel replies working after hot config reloads when a long-lived plugin monitor retains its startup config. Shared reply dispatch now always selects the Gateway's committed model-runtime publication, preserving exact catalog isolation and publication waits without restarting the monitor.
The shipped optional usePublishedModelRuntime SDK argument remains accepted, deprecated, and ignored until the next SDK major. Standalone dispatch and explicit per-turn overrides retain their existing contracts; transport durability remains owned by channel ingress.
The low-level regression delivers before reload, fails on the original code after reload with PreparedModelCatalogConfigReplacedError, and passes after the fix. Focused dispatch and sibling tests, standalone runner fixtures, build, and changed-file checks passed. A synthetic Gateway/channel/HTTP-provider harness delivered two replies around reload with the same Gateway process and monitor; real WeChat and Windows coverage remains unproven.
Fixes#146854
Related: #145563
Reported by @sunhsiao (#146854). Reproduction discussion and regression shape from @Lidashi1025 and @BronyaZaychik0328 (#145563).
## What Problem This Solves
An unrelated SQLite file with foreign-key violations could prevent every backup from completing.
## Why This Change Was Made
Whether an included file gets the live-database snapshot path is decided by exactly one mechanism at `src/commands/backup-resource-inventory.ts:336`, from the core set plus declared plugin resources. The online root snapshot supplies the registry used for discovery and traversal, so planning no longer needs a quiet write-ahead log.
## User Impact
Undeclared files survive backup unchanged with filename warnings. Foreign SQLite symbolic links that exceed the link-resolution limit (`ELOOP`), including loops, are skipped with a filename warning. Corrupt managed databases and unavailable plugin SQLite capabilities still stop publication.
## Evidence
- Pinned main `f0817f23e9`: the real CLI exits 1 on a structurally valid foreign database with a foreign-key violation and publishes no archive.
- Candidate `ce85d13530c4`: CLI create with verification, verify, and restore preserve seven foreign files and sidecars byte-for-byte, with one warning each. Corrupt core and unavailable plugin functions still refuse publication. Managed hardlinks include committed WAL data and restore identical images.
- Tested commit `37f9d97a9d65` (capture behavior unchanged): real CLI backup succeeds during 10 ms commits (309 rows during the 3.6-second run) and in the 100 ms control. Verify/restore retain identical valid root/alias images with writes committed during backup. The unrelated symlink loop is skipped with one warning and the archive restores successfully.
- The full architecture check passes with zero import cycles; five formatter/command tests pass. All 10 managed-refusal/older-schema command cases and changed-test checks pass. The separate macOS planning assertion noted below remains a baseline failure. Type checks and the test-partition check remain for CI.
## Compatibility
No schema, plugin fields, flags, or archive format change. Existing `backupResources` declarations define managed plugin data.
## Consumers
- `backup create`: preserves undeclared SQLite files and reports their filenames.
- `backup verify` and `backup restore`: treat files outside the captured core registry as opaque.
- `src/commands/migrate/apply.ts:26-41`: pre-migration backup now accepts unrelated foreign SQLite, returns only the archive path, and does not forward opaque warnings.
- Fleet backup: uses the shared archive metadata adapter to preserve independent hardlink entries without stalling.
- `formatBackupCreateSummary` moved unchanged to `src/commands/backup-summary.ts`; `src/commands/backup.ts` and `src/infra/backup-create.test.ts` import that owner.
census: generic formatBackupCreateSummary reviewed — 2 callers listed
## Invalidation
Ownership is frozen from the captured root registry for each backup; later registrations belong to the next capture. A plugin declaration changed after planning can be archived with payload classified by the earlier declaration.
## Contention
Registry discovery reads the online root snapshot before archive traversal. The 10 ms sustained-write test and 100 ms control both complete, verify, and restore successfully.
## Tests
- `backupCreateCommand`: all eight managed-refusal cases and both older-schema cases in `src/infra/backup-create.test.ts`; older-schema verification also uses `backupVerifyCommand`.
- `backupVerifyCommand`: all three opaque-file/sidecar cases in `src/commands/backup-verify.test.ts`.
- `backupCreateCommand` and `backupRestoreCommand`: opaque loop handling, declared/core loop refusal, and agent registration captured immediately before the root snapshot.
Those tables retain the complete case mapping, fixtures, and assertions. Source bytes are compared after capture or refusal and before the real outcome recorder runs; the recorder still runs unchanged. The unchanged macOS manifest-path assertion reproduces on base. The added source lines separate resource planning from captured ownership and preserve missing-root checks.
Thanks @clawputerlabs for the report.
Closes#144552.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* test(upgrade): assert explicit baseline plugin
* fix(session-share): hide subagents and tool activity
Publish only user and assistant conversation text from eligible root sessions. Preserve forks, redaction, read-only storage, and pagination; reject cursors from the previous mixed-item projection. Skip unrelated local adoption scans for publication-only catalog queries.
Give each catalog Worker a parent-owned capture directory. Release execution
at confirmed Worker exit and join detached advisory cleanup on pool close.
Preserve static Worker options, and fence synchronous cancellation during
preparation or construction before releasing ownership.
Make full-catalog test assertions follow the existing completed publication
after one bounded foreground request, preserving pending and cancellation
coverage and all production deadlines.
* fix(nextcloud-talk): reject excess concurrent webhook reads
Acquire a listener-owned in-flight limiter slot before the unauthenticated
webhook body read, reject overflow with a close-aware HTTP 429, and release
the slot after signature verification but before authenticated dispatch.
Incomplete requests previously pinned a pre-auth reader for the full timeout
without consuming the authentication-failure budget, letting any reachable
client hold unbounded numbers of sockets and readers to degrade webhook
availability. This follows the owner-level pattern merged for SMS (#136504)
and Feishu (#137230).
* fix(nextcloud-talk): preserve queued acknowledgements under pipelined overflow
Serialize webhook admission per connection through the shared HTTP request
lifecycle (runHttpConnectionRequest, re-exported on the plugin SDK guards
subpath) so a pipelined request's overflow rejection only starts after every
earlier response on the connection finished. Covers the reviewed sequence with
real TCP: a saturated keep-alive connection with admission pending past the
one-second close timer must still deliver the earlier signed 200 before the
close-aware 429.
* docs(nextcloud-talk): document overload admission and SDK connection ordering
Record the 64-slot admission bound, its close-aware 429 overflow behavior,
ordered keep-alive acknowledgements, and the unverified sender-redelivery
risk in the channel guide. Document runHttpConnectionRequest's
response-completion and closure semantics for plugin-owned webhook
listeners on the SDK infrastructure page.
* docs(nextcloud-talk): correct overload mitigation guidance
The 64-read admission budget is hard-coded and not configurable, so raising
reverse-proxy connection limits cannot relieve saturation and can feed more
requests into the rejection path. Advise reducing or buffering upstream
concurrency instead, and state plainly that the budget is fixed.
* feat(voice): unify Live sessions across calls and meetings
Resolve provider capabilities and interruption policy through the shared realtime voice owner. Keep meeting input isolated from virtual-microphone output, reuse native delegation for meetings and Voice Call, and preserve explicit Stop across browser and Apple relay clients.\n\nValidated with real Live API and synthetic Chromium/WebRTC proof, focused regressions, changed-file checks, and independent review. Related to #146289.
* test(voice): align capture fixtures and validation gates
Model browser audio capture in the shared meeting RPC fixtures so startup
failure tests reach the provider and verify capture cleanup. Preserve the
same relay startup behavior while simplifying duplicate lifecycle branches.
Rebalance the pre-existing 702-root platform test graph by moving security
tests beside sandbox/tool tests; keep coverage, graph counts, and limits.
* fix(meetings): preserve configured input commands
Keep explicitly configured capture/filter/mixer output as provider input on
local Chrome and paired nodes, preserving the v2026.9.4 contract. Generated
input and output-only overrides continue to use managed browser capture.
Retain Live's isolation guard and explain how to remove an input override
when selecting Live. Prove the actual PCM paths through both meeting engines
and transports, and document the preserved configuration behavior.
* fix(ui): surface coding session discovery controls
Add a sidebar shortcut and searchable session source settings for installed
Claude Code, Codex, OpenCode, and Pi plugins. Reuse the existing Gateway
configuration owner, including Pi's ACPX preference, and keep unavailable
schemas visible without permitting invalid edits. Preserve existing defaults.
* perf(ui): simplify session source menu navigation
* feat(node-host): advertise an explicit node command allowlist
Persist exact node command selection and restrict ancillary publication and hosting. Preserve the unchanged assertion baseline under the work-order stop rule; check:changed requests removing the obsolete runtime.ts count (2 to 0).
* feat(plugin-sdk): session transcript catalog reader
Expose bounded read-only native display pages and portable attribution through the existing runtime subpath. Keep pagination scoped to the original active transcript branch and allow an explicit bounded native cursor length.
* feat(session-share): read-only OpenClaw session catalog across paired gateways
Publish explicitly selected native session groups through two paired node commands. Validate the closed wire contract, reject remote profile claims, and keep receiver identity binding opt-in and display-only.
* fix(gateway): show published session catalogs to view-scoped roles
Let publication consent satisfy catalog read visibility for roles allowed to view others, while owner-only and unprofiled callers stay hidden. Preserve published attribution without accepting a remote local-session adoption claim. Regression tests reproduce four pre-fix failures; final validation stopped at the work-order baseline gate.
* docs: session sharing across gateways
Document sessions-only node setup, explicit publication groups, receiver attribution, view-scoped catalog access, and read-only limits. Add the bundled plugin inventory and generated reference entry. Live proof runbook remains outside the repository; build and rig execution are blocked by the work-order baseline restriction.
* fix(session-share): preserve source storage and paired reconnects
Respect configured stores through listing, paging, and revocation. Keep cold listings available and bound raw transcript reads. Prefer the established paired node credential on service restart, suppress unrelated host metrics, and refresh the approved plugin configuration docs.
* refactor(gateway): separate authorized catalog reads
Keep the catalog dispatcher within its owned scope and preserve post-read role checks and sender projection. Align the rebased tests with their shared setup and imports.
* fix(auth): keep synthetic auth discovery with its provider owner
Preserve auth-only descriptors and skip catalog-only matches before selecting a provider. Bound lightweight fallback to refs without a declared owner, so unrelated discovery failures cannot hide valid native auth or force unnecessary cold admission. Keep fresh external-auth capture and immutable plugin generation ownership intact.
* fix(auth): preserve provider match evaluation order
Match the provider reference before inspecting synthetic-auth hooks, preserving lazy descriptor selection while retaining the scoped discovery repair.
* chore(deps): advance cooled dependencies and major upgrades
* test(logging): migrate failed-sink regression to tslog 5
* test: retain dependency upgrade coverage within lint limits
* fix(deps): preserve compiler launches, Matrix sync and chat metadata
Keep copied script harnesses independent of declaration modules and preserve
Windows executable prefixes after admission. Audit the Matrix sync guard for
42.3, align CI toolchain/cache pins, and refresh session facts after accepted
model-catalog invalidation without relying on picker timing.
* fix(ui): preserve scoped session reconciliation after catalog refresh
* fix(discord): support continuous GPT Live conversations
Reuse the Gateway-owned GPT Live bridge for Discord voice, preserve speaker-bound agent delegation, and let Live own interruption while microphone input remains admitted during playback. Pace input continuously, play short replies, and preserve queued speech pauses. Document model-specific voice routes and unsupported host turn policies.
* fix(discord): preserve live voice admission and defaults
Keep unpinned realtime configurations on their provider default, ignore silent RTP for speaker retention, and retain live-policy freshness through roster enrichment and agent dispatch. Cover policy revocation during the real participant lookup path, fresh and existing model defaults, and idle speaker reclamation.
* test(discord): isolate delegation admission coverage
Keep the unchanged native delegation admission cases in a focused suite so the voice receive tests remain within the repository file-size limit.
* test(voice): prove delegated agent authority and cancellation
* test(discord): await continuous playback completion
* fix(codex): restore native discovery and hide empty catalogs
Use the node native Codex home for listing, transcript reads, and terminal resume without requiring the Gateway agent on the node. Keep Gateway ownership for adopted Chats.
Use native authentication for catalog connections, preserve primary source fingerprints during recovery, and let native clients start without an OpenClaw agent. Keep managed inference auth requirements and existing node permission boundaries.
Hide empty sidebar catalogs while continuing normal discovery refreshes.
* test(ui): cover catalog errors beside available sessions
* fix(codex): preserve node compatibility and hidden catalog paging
* fix: bound concurrent compute work and pending worker inputs
* fix: supply the host response budget in worker checkpoint tests
* fix: preserve prepared catalog ownership under admission pressure
* improve: keep image and PDF processing responsive
* fix: register PDF worker declarations in build fixtures
* test: rebalance SQLite checks into the state shard
* fix: resolve workers in standalone plugin packages
* docs: separate worker entrypoint guidance