@voltro/plugin-clickhouse 0.85.0 → 0.86.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -39,6 +39,672 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.86.0] — 2026-10-21
43
+
44
+ ### ⚠ BREAKING
45
+
46
+ - **Licensing refresh uses authenticated bounded JSON snapshots** — `@voltro/plugin-licensing`, `@voltro/cli`
47
+
48
+ License snapshot refresh accepts JSON containing a signed `token`, matching the Cloud license endpoint. Configure server-only `snapshotHeaders` for authenticated endpoints. Refresh refuses redirects, limits responses to 64 KiB and times out after ten seconds. Refusals retain the last verified snapshot under its existing expiry and grace rules and log only a fixed reason and optional HTTP status.
49
+
50
+ Custom endpoints returning a raw token must return the JSON envelope instead. The update command provides the endpoint and credential configuration steps. Unsigned response metadata never changes installed entitlements.
51
+
52
+ **`voltro update` carries you across this** — codemod `0.86.0/08_license-snapshot-envelope`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
53
+ - **Index draft and revision references with content writes** — `cms`, `cli`
54
+
55
+ Draft and history reverse-reference reads now query scoped stored edges, maintained in the content transaction. Apply cmsReferencesTable and backfill existing drafts and revisions with rebuildReferenceIndex before using reverse reads or replacement plans; the upgrade note covers tenant-scoped migration and rollback validation.
56
+
57
+ The references table now also stores draft and revision edges, told apart by a `stage` column. A query of your own on `CMS_REFERENCES_TABLE` that means live uses — a usage count, which pages show an asset, whether a file may become public — must filter `stage: 'published'`; otherwise a draft counts as a use, or opens a private file.
58
+
59
+ **`voltro update` carries you across this** — codemod `0.86.0/01_cms-reference-index-backfill`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
60
+ - **Reject environment values that would disappear from browser snapshots** — `@voltro/env`, `@voltro/cli`
61
+
62
+ Decoded environment values that JSON would omit, coerce or fail to encode now refuse boot by variable name. Defaults and explicit values use the field's existing decoder, bound to its own Effect instance.
63
+
64
+ Migration: ordinary `envVar` declarations need no changes. Custom `EnvFieldSpec` / `AnyEnvFieldSpec` decoders must return JSON-preserving values through plain `{ ok: true, value }` or `{ ok: false, message }` outcomes. Convert custom dates to ISO strings, and replace symbols, functions, bigint, non-finite numbers or cyclic values with a declared JSON representation. Keep decoding beside the schema using the same Effect instance.
65
+
66
+ **`voltro update` carries you across this** — codemod `0.86.0/05_environment-field-owned-decoder`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
67
+ - **Accept numeric store keys and normalize native numeric IDs** — `@voltro/database`, `@voltro/runtime`, `@voltro/testing`, `@voltro/voltro`
68
+
69
+ Keyed update, delete, hardDelete and patchJson accept numeric IDs directly, including tenant-scoped and transactional writes. SQL stores normalize numeric ID and numeric-reference results to the declared number type, matching the in-memory test store; text IDs remain strings. Numeric identities outside JavaScript’s safe integer range are refused rather than rounded.
70
+
71
+ Custom adapters consuming `RowKey` must handle numbers alongside strings before treating remaining keys as records, or use `rowKeyColumns`, `rowKeyIdentity` and `isCompositeRowKey`. Review string-ID workarounds and numeric identity ranges with the upgrade note.
72
+
73
+ **`voltro update` carries you across this** — codemod `0.86.0/04_numeric-store-keys`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
74
+ - **Registered session rotation preserves device revocation** — `@voltro/plugin-auth`
75
+
76
+ `rotateRegisteredSession` atomically replaces a current credential while retaining inactive device aliases. Signing out through any family member also ends its successor; other devices remain signed in. Failed persistence rolls back rotation. `findSession` and `listSessions` exclude rotated aliases, and revocation counts current credentials. PostgreSQL session persistence failures now fail issuance.
77
+
78
+ The sessions schema adds nullable `familyId` and `rotatedAt` columns and a family index. Review and apply the declared schema before restarting upgraded auth replicas. Applications declaring their own sessions table must mirror this shape. Registry touch/revocation writes now own a transaction; callers already inside a mutation or explicit transaction must pass `{ transaction: 'existing' }` to `dataStoreSessionRegistry`. Rotation accepts the same ownership option. The upgrade codemod reports the required schema and source review steps.
79
+
80
+ **`voltro update` carries you across this** — codemod `0.86.0/04_registered-session-device-rotation`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
81
+ - **Store release artifact byte counts beyond the 32-bit range** — `@voltro/plugin-releases`, `@voltro/cli`
82
+
83
+ Release artifact metadata now uses exact BIGINT storage while upload inputs and updater feeds retain numeric sizes up to Number.MAX_SAFE_INTEGER. Direct releaseArtifactsTable.size and ReleaseArtifactRow.size access now uses decimal strings; use BigInt(row.size) for exact arithmetic and supply strings in direct table writes. Run voltro db deploy before production startup to apply the safe integer widening; existing byte counts are retained. The update command reports direct table consumers for review.
84
+
85
+ **`voltro update` carries you across this** — codemod `0.86.0/09_release-artifact-byte-storage`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
86
+ - **Recover release file publishing without duplicate files or artifacts** — `@voltro/plugin-releases`, `@voltro/cli`
87
+
88
+ File publishers now preserve one operation identity through preparation, durable Storage tickets and release metadata. Retries, lost successful responses and renewed credentials return the original file and artifact without advancing the target or appending another event. Conflicting immutable intent is refused; current project authorization is checked on every attempt.
89
+
90
+ Deploy the updated API before the file CLI. File publication requires bound durable Storage operations, supplied by native default reference/grant stores. Custom publish facades must forward operationId and namespace Storage identity by canonical project/release; custom stores without that capability refuse file publishing. The registered manual upgrade explains the required review without changing authorization rules.
91
+
92
+ Metadata-only callers can supply operationId, including --operation-id in the CLI. This change does not reserve authority over a transfer, infer identities for prior unidentified uploads or automatically clean orphan provider objects.
93
+
94
+ **`voltro update` carries you across this** — codemod `0.86.0/10_release-upload-recovery`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
95
+ - **Required audit admission retains unknown invocation outcomes** — `@voltro/plugin-audit`, `@voltro/cli`
96
+
97
+ `auditPlugin({ invocationCapture: 'required' })` durably records a redacted action or workflow-start admission before its effect may run. It requires the datastore sink, both outcome outbox policies and `record: 'all'`. Failed or uncertain admission prevents execution. An interrupted admitted call retains an explicit unknown result; terminal outcomes correlate through `outcome.invocationId` without overwriting admission evidence. `AuditEvent.outcome` now includes `kind: 'unknown'`: update exhaustive sinks, redactors and views to distinguish it from success and error. Unknown does not establish rollback or permit automatic replay. Mutation, query and HTTP capture policies retain their own contracts.
98
+
99
+ `auditInvocationQuery()` filters and paginates logical invocations without deleting raw admissions; `auditInvocationIdentity()` supplies their stable display identity. Apply authorization and tenant filters using the `audit.` alias and retain raw row ordering keys for cursors. The nullable indexed lookup is derived from the protected outcome and checked during receipt replay and chain verification. `AuditLogTable` now requires full `SchemaTable` metadata; replace hand-built partial descriptors with the supplied `auditLogTable`.
100
+
101
+ **`voltro update` carries you across this** — codemod `0.86.0/05_audit-capture-contract-review`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
102
+ - **Physical storage namespaces preserve independent cleanup and shared bytes** — `@voltro/plugin-storage`, `@voltro/cli`
103
+
104
+ Separate reference rights from physical object ownership. Provider namespaces isolate operation replay and independent generations while sharing counts for actual shared bytes. Existing metadata requires an explicit stopped-replica after-schema assignment that preserves reference IDs, keys, grants, claims, quota and raw operation identities. Custom providers supply `objectNamespace`; direct DataStore metadata factories take an explicit storage scope. Preserve filesystem namespace markers with their volumes and finish returned retired-key cleanup through the matching service.
105
+
106
+ **`voltro update` carries you across this** — codemod `0.86.0/06_storage-object-namespaces`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
107
+ - **Storage replica inspection identifies and combines reference catalogues** — `@voltro/plugin-storage`, `@voltro/protocol`, `@voltro/devtools-ui`, `@voltro/cli`
108
+
109
+ `RefStore` requires a stable `catalogueId` effect. Default stores retain a schema-managed catalogue identity; direct DataStore adapters initialize it after schema reconciliation, and custom wrappers forward their underlying identity. Combined replica reads deduplicate shared catalogue rows and counters, preserve independent origins, and retain missing-replica evidence. Shared dashboards distinguish equal reference IDs from different catalogues and require one selected replica for file operations. Apply the normal schema before production boot and follow the upgrade note for custom stores and hosts.
110
+
111
+ **`voltro update` carries you across this** — codemod `0.86.0/07_storage-reference-catalogue-identity`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
112
+ - **Upload access policies reject oversized rule and principal arrays** — `@voltro/protocol`, `@voltro/plugin-storage`
113
+
114
+ Self-service upload policies accept at most 32 rules and 64 entries per rule's `roles`, `groups` and `scopes`. The same limits apply to server-approved upload policies and all four signed upload-ticket verifiers, before provider work. Previously accepted oversized policies are refused rather than truncated. Review upload defaults, authorization functions and custom ticket issuers before upgrading; use per-object grants for larger principal sets and restart outstanding upload sessions whose signed policies exceed the bounds. Existing stored references and grants are unchanged.
115
+
116
+ **`voltro update` carries you across this** — codemod `0.86.0/03_storage-policy-bounds`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
117
+ - **Bind upload tickets to shared metadata and physical storage** — `@voltro/plugin-storage`, `@voltro/cli`
118
+
119
+ All four upload-ticket families use version 2 and require a destination scope from the selected Storage service. A second replica with the same reference catalogue and physical bytes can accept the ticket. A different catalogue or physical namespace refuses it before provider work. Inspect tickets retain a separate signed issuer routing hint for the binary relay.
120
+
121
+ Renew outstanding version-1 upload tickets after coordinating issuers and receivers. Custom signers pass writeScope from the selected service's uploadTicketScope(); custom StorageServiceShape implementations provide that method. Preserve existing policy, attribution, limits and durable operation identity. Read grants and stored objects are unchanged. The registered manual upgrade covers custom issuers, metadata/provider identity and unfinished sessions; this does not add early revocation or automatic staged-object cleanup.
122
+
123
+ **`voltro update` carries you across this** — codemod `0.86.0/11_storage-upload-ticket-scope`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
124
+ - **Audit mutations can capture redacted intents transactionally** — `@voltro/plugin-audit`, `@voltro/protocol`, `@voltro/cli`
125
+
126
+ Add opt-in `mutationCapture: 'transactional-outbox'` for successful registered mutations with the datastore sink. Capture a redacted, actor-bound portable audit intent on the actual business transaction and deliver through the shared outbox handler using retained receipt identity. Failed required capture rolls back business writes; delivery retry/restart cannot rewrite a captured actor or duplicate a retained receipt. The default and non-success/action/workflow/HTTP recording remain best effort.
127
+
128
+ AuditEvent actor snapshots can be null as well as undefined; custom consumers must use a null-safe guard. PluginPermission now includes `outbox:handle`, so exhaustive maps and switches need deliberate handling. Existing one-argument `dataStoreAuditSink` calls remain valid; the optional receipt identity is for captured delivery retries. The upgrade codemod identifies affected imports and reports the review steps without automatically changing actor or permission policy.
129
+
130
+ **`voltro update` carries you across this** — codemod `0.86.0/05_audit-capture-contract-review`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.86.0).
131
+
132
+ ### Added
133
+
134
+ - **Project audit actor labels through a configured policy** — `@voltro/plugin-audit`
135
+
136
+ Add an optional `redactActor` policy to the audit plugin. Project resolved display-name and email labels before best-effort writes or required outbox capture while preserving immutable actor identity. Freeze the policy decision in each intent and reuse it during delivery and replay. Invalid required capture fails before commit; refusal admission preserves the original error.
137
+
138
+ Cloud activity capture and customer/operator history projections omit recognized credential-bearing actor labels and retain a safe immutable identity fallback. Historical stored bytes and hash links remain unchanged. The default plugin policy and row-history behavior are unchanged.
139
+ - **Reuse bounded interruptible HTTP ingestion** — `@voltro/plugin-storage`
140
+
141
+ `fetchIngestBody` exposes the same bounded HTTP byte reader used by Storage URL ingestion, including source checks, redirect limits and interruption. It reads bytes only; callers must apply their own authorization and persist through the complete Storage pipeline. It is not an RSS or zero-copy guarantee.
142
+ - **Caller-executed tools pause a mixed server tool loop** — `@voltro/ai`
143
+
144
+ Declare `execution: 'client'` on a tool to emit a marked pending call without a server executor or synthetic result. Server-only steps keep looping; send actual assistant/tool results in the next request to continue.
145
+ - **API builds include a readonly compiled migration planner** — `@voltro/cli`
146
+
147
+ API builds now emit a separate readonly migration-plan executable that runs with plain Node after runtime pruning. It uses the built application's module and SQL driver registries, preserves complete JSON plans and blocked exit-code semantics, and starts no application lifecycle or DDL execution. Schema-import failures refuse planning instead of emitting partial plans. Direct API and planner bundle entrypoints also correctly recognize execution through symbolic links.
148
+ - **Successful actions can retain audit outcomes for outbox delivery** — `@voltro/plugin-audit`
149
+
150
+ Add `successCapture: 'outbox'` for completed registered actions and workflow-start calls with the datastore audit sink. Captured outcomes retain their redacted payload and actor snapshot through sink outages, delivery retries and process restarts. Successful mutations keep their transaction capture without duplicate events. Failed outcome admission preserves the completed business result and reports a bounded diagnostic; external side effects and pre-admission process failures remain outside this delivery guarantee.
151
+ - **The devtools capsule shows what a page load waits for under `voltro dev`** — `@voltro/cli`, `@voltro/web`, `@voltro/devtools`, `@voltro/client`, `@voltro/protocol`
152
+
153
+ A full page load used to show nothing in the capsule while the dev server compiled and rendered the next page; only the browser's tab spinner moved. `voltro dev` now reports each page request to the tab that is waiting for it over the HMR socket, and the capsule shows `Loading /orders`, `Compiling /orders`, `Rendering /orders` or `Redirecting to /login` until the new page replaces the old one. If the navigation never replaces the page (a `204`, a download, or a stopped load), the status clears when the dev server reports how the request ended. A client-side navigation waiting for a page's code now shows `Loading page…`, or `Compiling page` while Vite compiles it. Previously it showed nothing. A lost dev server shows `Dev server offline`. Other tabs of the same app are not affected. A page navigation takes precedence over every other status: `DevStatus` gained an optional `priority`, and `selectDevStatus()` picks the status a single-status surface shows. A production build contains none of this.
154
+ - **Durable audit refusal delivery** — `@voltro/plugin-audit`, `@voltro/protocol`, `@voltro/runtime`, `@voltro/cli`
155
+
156
+ Add opt-in outbox delivery for failed registered mutations, actions and workflow starts after the business transaction settles. Capture redacted actor-bound intents and replay with stable receipt identity while preserving the original invocation error. Queries, transport failures, successful actions and unavailable-outbox admission remain outside this guarantee.
157
+ - **Declare PostgreSQL GIN trigram and JSON operator classes** — `@voltro/database`
158
+
159
+ `kindOptions.gin.opclass` declares an operator class for a single-column GIN index. Trigram indexes install pg_trgm before DDL. Schema creation, migration planning, catalog adoption, drift fingerprints and concurrent index creation retain the class; other dialects keep their documented GIN fallback.
160
+ - **A page's meta reads its locale's catalog as messages** — `@voltro/web`, `@voltro/i18n`, `@voltro/cli`
161
+
162
+ A page's `meta` function now receives `messages`: the message catalog of its locale, next to `locale`. A translated title reads `messages['meta.home.title']` instead of importing the catalogs into the page — a value import of every catalog put every language into that page's chunk, past the per-locale split. With `locales` in `app.config.ts`, the server, the prerender and the static shells hand `meta` the catalog of the render's locale. In the browser the document's own catalog is loaded before the first render, and a client navigation into another URL locale loads that locale's catalog and resolves `meta` again; until it arrives, the previous title stays. Without the i18n wiring `messages` is empty. Type it with the keys of your base catalog: `import type en from './en'` and `Record<keyof typeof en, string>`. The templates read their titles this way now.
163
+ - **Read native URL parameters without schema startup** — `@voltro/web`
164
+
165
+ Add `useUrlSearchParams()` for native, SSR-aware URL reads without schema decoding. Existing typed readers and setters retain their behavior. Router contexts and the request/router precedence are shared; schema-free link encoding no longer imports the decoder.
166
+ - **Outbox handlers publish declared events in the queued tenant** — `@voltro/cli`, `@voltro/runtime`
167
+
168
+ Effect outbox handlers can yield OutboxEventPublisher to publish declared events through the usual durable workflow and webhook audiences. Publication failure retries before delivery acknowledgment; the worker starts after its environment is ready. Queued user IDs do not restore request authority. Delivery remains at-least-once; use outboxId to deduplicate downstream effects.
169
+ - **Plugin outbox handlers use the shared delivery worker** — `@voltro/protocol`, `@voltro/runtime`, `@voltro/cli`
170
+
171
+ Server plugins can contribute `outboxHandlers` with the `outbox:handle` permission. Dev and compiled serve share handler registration, definition validation, collision refusal, inventory and the existing delivery worker. Runtime continues to export the canonical handler types. Retry budgets must be positive safe integers. Unknown effects remain pending without claim/release churn and cannot starve registered effects in the eligible batch. This contribution does not itself provide transactional audit capture.
172
+ - **Reuse plugin boot validation in server embeddings** — `@voltro/cli`
173
+
174
+ The server-only `@voltro/cli/startup` export provides the same permission audit and plugin lifecycle/configuration orchestration used by normal CLI starts. Embeddings can reuse these rules instead of maintaining a separate boot implementation. This does not isolate untrusted code or validate an entire application.
175
+ - **Explicit public documentation MCP providers** — `@voltro/mcp`, `@voltro/cli`, `@voltro/web`
176
+
177
+ Add explicit MCP content providers and a bounded stateless HTTP adapter, sharing the existing lifecycle and transport without exposing app inspection credentials. Ship bilingual public-content and WebMCP guidance in customer agent docs.
178
+
179
+ WebMCP execution tolerates early trial browsers without per-call options and always honors registration lifetime cancellation as well as browser cancellation.
180
+
181
+ Offer the existing WebMCP helpers through `@voltro/web/webmcp` so progressive browser integrations avoid importing the router, RPC client and i18n barrel.
182
+
183
+ Include islands imported by ancestor layouts in each page’s browser entry, preserving client detection and provider-boundary guards.
184
+
185
+ `routeHttp` keeps its name and fields: `RouteHttpOptions` now extends a shared base and the function also accepts the new `ProviderRouteHttpOptions`, so every existing call still compiles (the golden lines change, nothing is removed or narrowed).
186
+ - **Run trusted release management in the caller transaction** — `@voltro/plugin-releases`
187
+
188
+ Release plugin instances expose validated server-side management Effects that join an explicit caller transaction, so application authorization and native release metadata writes can commit or roll back together.
189
+ - **Bind authenticated requests to independently selected tenants** — `@voltro/protocol`
190
+
191
+ `composeAuthStrategies` accepts a `requestedTenant` source alongside fresh `memberships`. Explicit targets are authorized before scopes and guards, take precedence over stored selection without changing it, and fail closed when invalid or no longer permitted. Live authority revalidation repeats the same membership check. Missing hints retain existing behavior. This is a low-level composer primitive; it does not add an app-config option or automatically wire client, SSR, or loader workspace context.
192
+ - **Configure request-local tenant binding in API auth** — `@voltro/cli`
193
+
194
+ API applications can configure `auth.requestedTenant` alongside fresh `auth.memberships`. Development and compiled production starts pass the whole configuration through the shared auth builder. Explicit targets are authorized before scopes and guards without changing persistent selection. No default header convention is introduced; clients, SSR and loaders must supply their workspace context consistently.
195
+ - **Require explicit resource verdicts for scope guards** — `@voltro/protocol`, `@voltro/devtools-ui`
196
+
197
+ Scope guards can declare `resourceOnly: true` to require the registered resource resolver's verdict even when the subject holds the scope globally or has `admin:full`. Missing resources or resolvers, invalid selectors, and failed resolver Effects refuse access. Existing scope guards keep their global-grant behavior.
198
+
199
+ Inspection panels recognize canonical scope refusals without an HTTP status and show the localized access-recovery message instead of exposing a structured error as text.
200
+ - **REST routes declare CORS, bearer access and quotas** — `@voltro/protocol`, `@voltro/runtime`, `@voltro/cli`, `@voltro/plugin-ratelimit`
201
+
202
+ REST descriptors accept `cors`, `credentials: 'bearer'` and `rateLimit`. Matching responses include CORS through framework refusals and OPTIONS; bearer routes discard cookies and bypass only their own method's origin guard. Quotas use the mounted rate-limit plugin and fail to mount when it is absent.
203
+ - **Pending UI submissions survive editor destination changes** — `@voltro/devtools-ui`
204
+
205
+ Expose `useScopedSubmissions` to retain a synchronous submission lease above editors that remount for another destination. Returning to the same destination retains its pending guard; unrelated destinations remain usable, and an old release cannot unlock a newer operation. The primitive guards mounted UI submission and does not replace server authorization, durable receipts or uncertain-outcome recovery.
206
+ - **Control the tenant mixin index when a composite covers reads** — `@voltro/plugin-multitenancy`
207
+
208
+ `tenant({ index: false })` omits the automatic tenantId index when an application declares a covering composite B-tree. The default remains indexed; tenant isolation and audit stamping are unchanged.
209
+ - **Required mutation hooks share the transaction outbox facade** — `@voltro/protocol`, `@voltro/runtime`
210
+
211
+ Required mutation contributions receive the same enqueue-only outbox facade as the executor for the current transaction attempt, when handlers are registered. Business data and intent commit or roll back together; delivery nudges survive only successful commits. Dev and compiled serve also supply runner start and elapsed timing. Existing Runtime enqueue option exports retain their canonical Protocol contract. This capability alone does not adopt required audit capture or make actions/workflows transactional.
212
+ - **Plugins can store required records before a mutation commits** — `@voltro/protocol`, `@voltro/runtime`, `@voltro/cli`
213
+
214
+ Plugins can declare `beforeMutationCommit` to write required records or durable intents through the actual mutation transaction. A failure rolls back business data and participant writes together; contention retries replay both. Development and compiled production starts share the hook, with explicit interception and write permissions. Existing RPC interceptors and best-effort audit logging retain their behavior. External I/O belongs after commit and needs durable, idempotent delivery.
215
+ - **Install portable UI source into React library packages** — `@voltro/cli`
216
+
217
+ `voltro ui init/add/status/update --package <path>` installs and tracks registry source in a named React library. Local imports are relative to their installed files, preserving full license headers and the ordinary protection for edited source. Select either a web app with `--app` or a library with `--package`.
218
+ - **Initialize new web apps with Voltro UI and conditional agent guides** — `@voltro/cli`
219
+
220
+ `voltro create-project --ui-library voltro-ui` initializes the selected web template with Signal, local fonts, component configuration and a UI source lock before the normal package installation. `--ui-registry` selects an alternative HTTPS or loopback registry. Agent guides expose the UI source reference only for workspaces and web apps with a valid UI lock.
221
+ - **Install and update UI source while preserving local edits** — `@voltro/cli`
222
+
223
+ `voltro ui init`, `add`, `status` and `update` manage Base UI components in Voltro web apps with exact registry versions and a checked-in file-hash lock. Updates preserve edited or deliberately deleted files, place conflicting new source beside the original, and report removed items with their supplied attribution link. Initialization installs local theme and font assets; status can adopt byte-identical source installed through the shadcn CLI.
224
+ - **Report UI source updates after framework upgrades** — `@voltro/cli`
225
+
226
+ Framework updates report different or pending versions and removed items from existing UI source locks, with a separate `voltro ui status` review command. Registry failures remain explicit advisory failures; copied source and UI locks are never changed by the framework update.
227
+ - **Install Theme Studio share links in fresh web apps** — `@voltro/cli`
228
+
229
+ `voltro ui init --theme <link>` installs the exact theme encoded in a Theme Studio share URL with full MIT attribution. The lock retains its source URL and file hashes, so status and update keep that theme identity and preserve edited or deliberately deleted files. Theme URLs use HTTPS or loopback HTTP, refuse redirects and retain the existing response-size and timeout limits.
230
+ - **A shared web optimization skill for Codex and Claude Code** — `@voltro/cli`
231
+
232
+ New projects receive `voltro-optimize`: a repeatable Lighthouse and browser pass covering performance, accessibility, best practices, SEO and agentic browsing, with targets by website type, intentional noindex exceptions and before/after evidence. The skill library keeps canonical Claude entrypoints and seeds Codex references to the same instructions. Agent guides include the website quality targets; existing projects can add missing skills with `voltro agents-md` without overwriting their own files.
233
+ - **Recover stopped workflow starts with proven non-dispatch** — `@voltro/workflow`, `@voltro/cli`, `@voltro/voltro`
234
+
235
+ Add read-only `voltro workflows flow submissions` and `flow recover <submissionId>` previews, with explicit `--commit --attempts N --stopped-at N` recovery for completed transfers that prove engine dispatch never began. Recovery retains the original input, reservation and lifetime attempt count, grants a fresh configured retry budget, and preserves ambiguous acceptance. Reusing the same stop token safely reconciles a lost response without reopening a later stop. Commit requires one selected API target and the separate Inspect write credential. Low-level failure and rejection helpers add an optional observed recovery epoch; pass the submission's `retry.recovery?.attempts ?? 0` so delayed failures cannot consume the new budget.
236
+
237
+ ### Changed
238
+
239
+ - **A page downloads the message catalog of its language only** — `@voltro/cli`
240
+
241
+ With `locales` and `src/locales/<code>.ts`, the generated entry imported every catalog statically, so each visitor downloaded every language in the app's entry. `voltro build` now gives every catalog its own chunk: the entry loads the one of the language the server rendered before its first render — nothing renders untranslated and hydration matches — and the server announces it as `modulepreload` in that document, so it downloads with the entry. Measured on an app with English and German catalogs: about 30 KB gzip less per first load. `voltro dev` keeps the catalogs static, so an edited catalog still hot-updates.
242
+ - **Reject unsupported data flags before loading command execution** — `@voltro/cli`
243
+
244
+ Invalid `voltro data` flags now return their existing message and exit code sooner, before loading database, storage and transfer execution modules. Valid commands retain the same validation and execution path.
245
+ - **Pages that read no data hydrate without loading the rpc runtime** — `@voltro/web`, `@voltro/client`, `@voltro/cli`
246
+
247
+ An app with `apis` and routes no longer carries its rpc runtime — the client, the WebSocket transport, the subscription cache, Effect and the api schemas — in its first load. The generated entry calls the new `mountWithDeferredApis`; `voltro build` reads each route's page, its layouts and the files they import for a data hook and loads the runtime together with the routes that use one. Every route's HTML now also announces its page chunk (and, for a route that reads data, the runtime) as `modulepreload`, so both download with the entry instead of after it. Measured under a throttled connection on an app with one api: a page without data hydrated 1674 → 975 ms with 145 → 78 KB of JavaScript before it; a page with one subscription hydrated 1692 → 1456 ms and showed its first data 2001 → 1805 ms. The runtime still arrives on every page — after the first commit under `web.api.connect: 'eager'`, when the page is idle under `'lazy'` — so connections open as before. A data hook the build cannot see waits for the runtime instead of failing. `FrameworkRuntimes` gains an optional `ready()`; `ApiRuntimeController`, `createApiRuntimeController`, `deferredApiRuntime`, `builtApiRuntime` and `toMountedApis` are new exports the generated entry uses.
248
+ - **Apps without apis load about 40% less JavaScript before they are interactive** — `@voltro/web`, `@voltro/client`, `@voltro/cli`
249
+
250
+ An app whose `app.config.ts` declares no `apis` no longer ships the rpc runtime. The generated entry now calls the new `mountWithoutApis(App, options)` instead of `mount(App, { apis: {} })`: same platform, hydration, islands, store seeds, service worker and Devtools, with empty runtime contexts and no supervisor, WebSocket transport or subscription cache. The router reads the browser half of a loader's `ctx.query` from the runtimes the boot provides (`FrameworkRuntimesProvider`'s new optional `queryOnce`) instead of importing it, so it no longer pulls the Effect runtime into every entry chunk; a provider mounted by hand without `queryOnce` leaves `ctx.query` undefined in the browser, as for an app without apis, and the development console bridge, server log relay and trace overlay load only in a development build. Measured on an app with pages, layouts, i18n and client stores but no apis: first load 179.7 → 105.8 KB gzip; with one form page added, 206.1 → 106.2 KB gzip. Apps with apis lose about 2 KB gzip. `window.voltroDiagnostics`, the support control for api sockets, now exists only in apps that mount an api.
251
+ - **A route group's layout loads only with the routes under it** — `@voltro/cli`, `@voltro/web`
252
+
253
+ The generated route table imported every layout of every route group statically, so a public page downloaded the app area's layout and everything it imports — its data hooks, schemas and rpc helpers included. `voltro build` now loads a layout in parallel with the page chunk of a route under it, and the route's HTML announces both as `modulepreload`. The root layout and the layouts above a `loading.tsx` (whose skeleton renders inside them) stay in the entry. A not-found inside such a group loads the group's layouts before it renders; `NotFoundDescriptor` gains an optional `load()` for that, and `preloadRouteModule` takes the not-founds so an unmatched URL hydrates inside its layouts. A route's initial stylesheets now also include its nested layouts' CSS, which was looked up under the wrong path. Measured on an app with a public site and an editor area: its public pages' first load went from 162 to 108 KB gzip, together with this release's fix for `errorMessage`. `voltro dev` keeps every layout static, so layout hot updates are unchanged.
254
+ - **Pages ship only the package code they reach** — `@voltro/client`, `@voltro/web`, `@voltro/protocol`, `@voltro/i18n`, `@voltro/ui`
255
+
256
+ Every published `@voltro/*` package now keeps one file per source module in `dist/` instead of merging its modules into a few shared files. A bundler assigns whole files to chunks, so with the merged files one page that used a form helper put `@voltro/client`'s form engine, `@tanstack/form-core` and its schema code into the entry chunk every page loads (+26.3 KB gzip on an app with one form page). Your app's bundle now splits these packages as finely as their source. Import paths and public exports are unchanged.
257
+ - **Reduce runtime loading for primary SQL commands and storage configuration** — `@voltro/cli`, `@voltro/plugin-storage`
258
+
259
+ Load memory-store, replica-routing and URL-ingestion runtime code only when used, retaining the shared store behavior and all URL safety checks.
260
+ - **Projected HTTP failures reuse private schema tag metadata** — `@voltro/protocol`
261
+
262
+ Mounted public API routes reuse private metadata for immutable Effect error schema ASTs instead of retraversing tagged schemas on each failure. Replacement schemas, per-failure status and headers, shared guard errors and undeclared failure behavior remain visible.
263
+ - **Distinguish requested tenant refusal from rejected credentials** — `@voltro/protocol`, `@voltro/runtime`
264
+
265
+ Request-local tenant selection now reports `RequestedTenantRefused` separately from rejected credentials. Its typed reason describes an invalid target, missing membership or unavailable selection source. HTTP and WebSocket middleware preserve the error, and live computed subscriptions terminate when workspace access is withdrawn. Credential rejection still reports `Unauthenticated`; clients must reserve session invalidation for that error. No user-authored API is removed or renamed.
266
+ - **Namespaced web optimization skill for customer projects** — `@voltro/cli`
267
+
268
+ Seed `voltro-optimize-web` for website and UI optimization, with one canonical Claude skill and a Codex reference to the same instructions. All supplied Voltro skills use the `voltro-` namespace. Existing project-owned skills are preserved.
269
+
270
+ ### Fixed
271
+
272
+ - **Wait for RPC readiness before sending actions** — `@voltro/client`
273
+
274
+ Wait for RPC protocol recovery before sending new actions after a detected connection outage, including reads retried during API reconnection. Resolve the current runtime after readiness, bound the wait and cancel queued intent on user or organization changes. Preserve SSR/StrictMode boot resolution. Already sent actions are not automatically replayed after an uncertain response.
275
+ - **Preserve audit and row-history actor snapshots on real stores** — `@voltro/database`
276
+
277
+ Resolve audit and row-history actor snapshots with canonical database predicates, so real stores preserve the matching actor identity instead of silently dropping it.
278
+ - **Schedules and workflows can refresh live aggregates** — `@voltro/cli`, `@voltro/runtime`
279
+
280
+ Scheduled and workflow handlers receive the live aggregate registry in development and production. Calendar cron policies already execute at the declared timezone boundary; stale type comments no longer describe them as deferred.
281
+ - **Validate artifact batches before publishing bytes** — `@voltro/cli`
282
+
283
+ Release file uploads reject missing or conflicting metadata flags before uploading. Desktop publishing validates manifest metadata, complete file batches and declared signatures against their hashes and sizes before remote writes, then uploads private stable snapshots without retaining the whole batch in memory. Release upload keeps its artifact `--url` separate from API selection through `--target`.
284
+ - **Audit appends recover without artificial chain gaps** — `@voltro/plugin-audit`
285
+
286
+ Datastore audit sinks serialize each writer's append attempts and derive links from persisted state where reads are available. Failed inserts no longer consume chain positions. A stable optional receipt ID lets durable delivery handlers deduplicate identical retained events across retries and restarts; different content or tampered receipts are refused. Default best-effort audit capture remains unchanged.
287
+ - **Hydrate automatic islands as interruptible React work** — `@voltro/web`
288
+
289
+ Schedule automatic island hydration as interruptible React work while retaining foreground hydration for interaction-triggered islands.
290
+ - **Stream billing read models after subscription changes** — `@voltro/plugin-billing`
291
+
292
+ Billing subscription and entitlement queries now stream updates when their subscription rows change. Invoice queries react to invoice and customer-link changes. Existing subscribers receive the current result after cancellation, resumption, provider webhooks or reconciliation without polling or reloading. Tenant and permission checks remain active on every recomputation.
293
+ - **Billing private URLs recheck current authority after provider IO** — `@voltro/plugin-billing`
294
+
295
+ Checkout and customer-portal URL routes reauthenticate their bound principal and tenant and recheck the declared manager guard before returning a provider URL. Withdrawal during provider IO refuses the late result without undoing or replaying the provider operation.
296
+ - **Prioritize rendering assets during browser startup** — `@voltro/cli`
297
+
298
+ Production browser entries use native ESM dependency loading instead of generated JavaScript module-preload hints. This avoids synchronous link insertion during route loading. Deferred features still load their CSS before module execution.
299
+ - **Preserve all own JSON fields in approval identities** — `@voltro/runtime`
300
+
301
+ Preserve all own JSON fields when deriving approval payload identities, including `__proto__`. Nested content changes can no longer disappear through an object prototype setter during canonicalization. Object key ordering stays stable; inherited fields remain excluded.
302
+ - **The MySQL/MariaDB CDC gate now cancels paired expiry timers, as 0.85.0 described** — `@voltro/sql-mysql`
303
+
304
+ The 0.85.0 notes listed "Release paired CDC expiry timers immediately", but that code did not reach the release: the inline/binlog delivery gate still counted unpaired occurrences and let every timer run out. It now cancels a fingerprint's timer as soon as its echo pairs, and each expiry belongs to its own generation, so an old callback cannot expire a newer identical write. Unpaired events keep their expiry and first-arrival delivery.
305
+ - **Restore Cloud environment CLI access and faithful non-secret export** — `@voltro/cli`
306
+
307
+ Cloud environment commands accept `--env <slug>` and report the actual selected environment. Without it, the configured project default applies. Listings and dotenv export contain only non-secret project variables; CLI writes cannot turn an existing secret into plaintext. Current role, membership and credential authority remain required.
308
+
309
+ `env pull` atomically writes an owner-only `.env.cloud` and validates faithful dotenv literals before changing the previous file. Invalid targets, responses or unrepresentable values refuse without overwriting it. Use a dotenv reader rather than sourcing the file as a shell script. No user-authored source migration is required.
310
+ - **Bind Cloud rollback to its inspected environment and artifact** — `@voltro/cli`
311
+
312
+ The launch-gated Cloud rollback command now inspects and submits the exact environment, current and previous deployment IDs, image reference, digest and commit. Explicit `--env` selection cannot silently fall back; omitted selection uses the configured app override or project default. A changed target is refused, and repeated confirmations reuse the matching in-flight queue item.
313
+
314
+ `--no-watch` returns after queue acknowledgement; together with `--json` it prints that acknowledgement as JSON. The normal command still waits for a terminal deployment status. An accepted queue item does not establish runtime health. The launch default remains closed. No user-authored source migration is required.
315
+ - **CMS template content reads serialize native timestamps** — `@voltro/cli`
316
+
317
+ The CMS API template serializes native database timestamps as ISO strings in draft, published and release-perspective content reads. Existing documents now open through the JSON output boundary without rejecting their stored creation timestamps.
318
+ - **Preserve request-scoped preload seeds in compiled server renders** — `@voltro/client`, `@voltro/web`, `@voltro/cli`
319
+
320
+ Compiled server renders preserve subscription and client-store seeds when page and renderer code load separate framework module instances. Resolver hooks and the server's AsyncLocalStorage share one process identity, while each request retains its own seed bags. Returned SSR and deferred SPA stream callbacks restore the captured request scope when the HTTP handler dispatches them. Concurrent renders cannot mix hydration data.
321
+
322
+ Existing seeding APIs and their server-only contract remain unchanged. Live subscriptions still replace initial seeds after the browser connects.
323
+ - **Migration recovery validates the complete execution receipt** — `@voltro/database`, `@voltro/cli`
324
+
325
+ Resuming a migration whose completed history already exists now validates the exact ordered operation receipt, including serialized defaults and duplicate counts. A reordered, incomplete or extra-operation receipt refuses recovery without clearing the operation ledger or replacing historical metadata. Valid recovery retains the original receipt and skips work already completed.
326
+ - **Computed queries stop delivering after authentication ends** — `@voltro/runtime`
327
+
328
+ Computed query subscriptions report `Unauthenticated` and stop delivering when authentication is withdrawn during recomputation, as they already do for `ScopeError`. They no longer silently remain on the last value after a session ends or an account is deactivated. Restoring access requires a newly authorized subscription; ordinary non-authorization recompute failures retain their existing behavior.
329
+ - **Computed queries observe both sides of tenant transitions** — `@voltro/runtime`
330
+
331
+ Computed subscriptions now invalidate when a source row moves out of their tenant as well as into it. This rechecks ongoing authorization before recomputation and terminates revoked subscriptions with the typed refusal. Events confined to other tenants retain the existing fast skip.
332
+ - **Computed queries terminate on typed access revocation** — `@voltro/runtime`
333
+
334
+ Reactive computed queries preserve typed `ScopeError` and `Unauthenticated` failures from Effect executors during recomputation. The dispatcher ends the revoked subscription with its access error instead of treating Effect's failure wrapper as a temporary computation failure and silently retaining the last value. Request cancellation still interrupts the computation. Ordinary transient computation failures retain the existing recovery behavior.
335
+
336
+ Custom access checks must declare their authority tables in the query's `source` alongside its data dependencies. The regression tests run the actual producer and dispatcher through source changes, access revocation and subsequent regrant.
337
+ - **Recheck computed query authority across source workspace IDs** — `@voltro/protocol`, `@voltro/runtime`
338
+
339
+ Computed subscriptions now recheck every change to a declared source even when its row carries another workspace's tenant ID. Global account and membership state can affect subscriptions across workspaces; row-image routing could leave those subscriptions with stale authority. Executors still enforce current access, live reauthorization preserves requested-tenant refusals as typed denials, revoked subscriptions terminate, and unchanged results are suppressed. Descriptor row matching is unchanged. No user-authored API is removed or renamed.
340
+ - **Recognize configured test setup files as fixture consumers** — `@voltro/cli`
341
+
342
+ Doctor parses configured Vitest setupFiles and globalSetup entries, including static aliases, spreads, roots and nested projects, without executing configuration. Test-only helper chains may import fixtures; production paths still fail the boundary.
343
+ - **Confirmation controls never submit surrounding editor forms** — `@voltro/devtools-ui`
344
+
345
+ `ConfirmMutationButton` and `ConfirmAction` use non-submit buttons for opening, confirming and cancelling an operation. Placing a confirmation inside an editor no longer also submits that enclosing form. Only the explicit confirmation callback runs the operation.
346
+ - **Confirmation dialogs keep viewport gutters and bounded height** — `@voltro/devtools-ui`
347
+
348
+ Confirmation dialogs use valid calculated width and height limits, preserving viewport gutters on mobile and scrolling long content within the available height. Their shared confirmation panel uses the standard one-pixel accent edge.
349
+
350
+ Dashboard hosts scan nested built shared UI modules so confirmation positioning and other component utilities remain in generated CSS after modular builds.
351
+ - **Mutation confirmations survive disappearing live rows** — `@voltro/devtools-ui`
352
+
353
+ `ConfirmMutationDialog` lets a stable parent retain an operation's captured selection when optimistic or live changes remove its trigger. The dialog keeps pending requests locked and refusals visible instead of losing them with a row. Confirmations initially focus Cancel and can use `returnFocusTo` to restore keyboard focus when the original trigger disappears. `ConfirmMutationButton` uses the same implementation.
354
+ - **Data explorer waits for verified table metadata** — `@voltro/devtools-ui`
355
+
356
+ The data explorer now shows clear loading, retryable failure and unavailable-table states before rendering a selected table without its catalogue metadata. It no longer displays a zero-column grid, row actions or misleading pagination after an initial catalogue failure. Failed refreshes retaining verified metadata keep the grid, reviewed drafts and pending write locks in place.
357
+ - **Descriptor queries decode encrypted storage** — `@voltro/cli`
358
+
359
+ Development and compiled production API starts now give the reactive dispatcher the existing storage codec. A descriptor query's initial RPC snapshot and live deltas return decoded `.encrypted()` values instead of physical ciphertext. Request-scoped writes remain encrypted at rest. Query authorization, row filters, wire-column visibility and production inspection masking remain independent.
360
+
361
+ The regression exercises an actual production RPC listener, the normal REST projection, a dispatcher snapshot and a persisted update followed by its live delta. Separate native acceptance checks cover a compiled PostgreSQL target.
362
+ - **Preserve universal desktop targets and offer compatible update artifacts** — `@voltro/cli`, `@voltro/plugin-releases`
363
+
364
+ Desktop manifests retain universal macOS targets and use explicit Rust build context for unqualified bundle paths instead of assuming Intel. Ambiguous targets are refused before uploads. Signed universal Mac updates serve both native architectures while signed concrete builds take precedence; architecture-specific downloads refuse incompatible fallbacks.
365
+ - **Development-only diagnostics work again in apps installed from npm** — `@voltro/web`, `@voltro/devtools`
366
+
367
+ The published packages had `import.meta.env.DEV` replaced with `false` when they were built, so under `voltro dev` an app installed from npm never forwarded browser `console.*` calls to the terminal, never relayed server logs into the browser console, never showed the trace error overlay, never armed the reload backstop for a wedged socket and never printed the islands-mode notice. The packages now leave `import.meta.env` to your app's build, which keeps all of these in development and removes them from production.
368
+ - **Development islands retain configured font assets** — `@voltro/cli`
369
+
370
+ Development islands pages retain configured font definitions, CSS variables and preloads in their initial HTML, matching built pages without loading the full application entry. This prevents pages from falling back to the browser's default typeface.
371
+ - **Devtools capsule keeps form labels readable** — `@voltro/devtools`
372
+
373
+ The closed Devtools capsule now considers visible form labels and fieldset legends when temporarily moving away from page content. This keeps field names and accompanying status text readable on narrow screens while preserving the saved dock position and keyboard access to the overlay.
374
+ - **Developer capsule keeps interactive content clear** — `@voltro/devtools`, `@voltro/devtools-ui`
375
+
376
+ Keep the closed development capsule clear of table cells and live/error messages, including updates to existing text nodes. Use a compact accessible status mark when only a narrow free area remains, restoring the full face when space becomes available. Preserve the saved dock position. Data explorer query errors announce themselves as alerts while retaining their existing recovery controls.
377
+ - **Keep the closed Devtools capsule clear of page controls** — `@voltro/devtools`
378
+
379
+ The closed in-page Devtools capsule temporarily moves to nearby free space when it would cover a visible page control, heading or paragraph. Layout changes are observed without polling or network calls. The saved dock preference is preserved, and dragging starts from the displayed position. A viewport without free space retains the preferred position.
380
+ - **Companion warnings follow the resolved dependency graph** — `@voltro/cli`
381
+
382
+ The Effect companion warning follows the app and CLI dependency links. Unreferenced pnpm virtual-store folders left behind by an override and frozen install no longer keep a mismatch warning active; reachable transitive mismatches still produce the repair instruction.
383
+ - **Effect 4 migration repairs asserted Result value reads** — `@voltro/cli`
384
+
385
+ `voltro update` repairs `left`/`right` reads through TypeScript assertions, non-null assertions, parentheses, local aliases and literal bracket keys when the value comes from a Result decoder or guard. Inline assertion fields become `failure`/`success` as well; computed keys and named assertion types receive review markers. A repair codemod also reaches projects already upgraded to Effect 4.
386
+
387
+ Saved schema decoders and unevaluated Effects or Promises retain their own metadata. The repair follows decoder calls and Results extracted through `yield*`, `Effect.runSync` or awaited `Effect.runPromise`. Reassigned bindings and conflicting declarations receive manual-review markers instead of guessed field renames, and alias discovery terminates on conflicting origins.
388
+ - **Effect 4 upgrades flag ignored schema parsing annotations** — `@voltro/cli`
389
+
390
+ `voltro update` warns when a schema annotation supplies `parseOptions`, including through local annotation aliases and spreads. Effect 4 ignores these annotations: move parsing options to decoder calls, or enforce reusable strict contracts with `StructWithRest` and `isPropertyNames` checks. Test unknown-key rejection at the actual decoding boundary; the repair codemod also reaches already-upgraded projects.
391
+ - **Redact credentials embedded in diagnostic strings** — `@voltro/logger`
392
+
393
+ The default logger recognizes its supported credential formats inside longer strings and replaces the entire message, field or plain-object cause value. Ordinary identifiers and non-sensitive explanations remain unchanged. Explicit key-only redactors retain their existing behavior.
394
+
395
+ Cloud organization-operator capture sanitizes retained target and explanation text with the same primitive. Privileged history reads also sanitize older context without rewriting its stored bytes or audit hash chain. Format matching does not classify arbitrary opaque secrets or `Error` instance internals.
396
+ - **A precompiled voltro start validates env fields with their own effect copy** — `@voltro/env`, `@voltro/cli`
397
+
398
+ A web app whose `app.config.ts` declares an `envVar.url()` refused to boot under a precompiled `voltro start` as soon as that variable was set: `FATAL: precompiled voltro start failed to load: Cannot convert a Symbol value to a string`. The start bundle validated the app's env schemas with its own copy of `effect`, whose parser does not recognise the other copy's internal sentinels, so the URL check received a symbol. Every env field now carries a decoder bound to the copy that built its schema, and boot validation goes through it.
399
+
400
+ `EnvFieldSpec` and `AnyEnvFieldSpec` gain a required `decode`. Fields are produced by the `envVar.*` builders, which set it; a field object written by hand would now need it, which no documented API asks for.
401
+ - **errorMessage in an error boundary no longer pulls Effect into every page** — `@voltro/protocol`, `@voltro/client`
402
+
403
+ `errorTag`, `errorMessage` and `reportableError` lived in the module that defines the procedure schemas, so calling `errorMessage` in an `error.tsx` — which is in every page's entry — put Effect's schema code into the first load of every page (about 140 KB raw). They now live in a module of their own with no imports. Imports and behavior are unchanged.
404
+ - **Redact recognized credential formats from diagnostic values** — `@voltro/logger`
405
+
406
+ Recognize source-defined Voltro service, invitation and publish credential value formats in the default logger redactor, including bare values and embedded URLs or diagnostic text. Match the full token body and identifier boundaries so ordinary invitation IDs and longer unrelated identifiers retain their meaning. Explicit key-only redactors keep their existing contract.
407
+
408
+ Cloud audit capture and customer/operator history projection reuse this shared format policy. Historical bytes and hash chains remain unchanged; projection does not erase secrets stored by an older policy.
409
+ - **Doctor recognizes configured Vitest setup consumers** — `@voltro/cli`
410
+
411
+ The fixture import audit recognizes statically configured Vitest setupFiles and globalSetup entries, including test helpers they import. Only the selected configuration’s statically reachable default export grants an exemption; unused examples, overridden declarations and unknown configuration remain checked. Configurations are read without execution. Side-effect imports and production paths into a setup entry remain checked.
412
+ - **Invalid fluent filters fail before reads or writes** — `@voltro/runtime`
413
+
414
+ Fluent `where` filters now reject unsupported comparison operators, invalid argument counts, and non-string column names before accessing data. An unknown operator no longer silently becomes equality for selects, updates, or deletes. Use `contains` or `startsWith` for literal text matching; two-argument equality and predicate helpers keep their existing behavior.
415
+ - **Gateway catalogs retain new model types under the unknown filter** — `@voltro/ai`
416
+
417
+ Both gateway catalog readers normalize unrecognized model types to `unknown`, keeping them visible through the existing modality filter when a supported AI SDK update introduces new classifications. The HTTP catalog preserves the original model type in `raw`.
418
+ - **voltro dev no longer corrupts the app's .gitignore while booting** — `@voltro/cli`
419
+
420
+ `voltro dev` adds `app.manifest.generated.json`, `app.graph.observed.generated.json` and, when it mints a secret, `.env.local` to the app's `.gitignore` from separate boot tasks. Their read-modify-write cycles interleaved: projects ended up with lost entries and stray fragments such as `a` or `.json`, and generated files the framework meant to ignore were committed. One writer now adds missing lines in a single synchronous step, never rewrites what is there, and reports instead of failing when the file cannot be written.
421
+
422
+ Check your apps' `.gitignore` files for single-word fragments left by earlier boots, and untrack `app.manifest.generated.json` / `app.graph.observed.generated.json` if they were committed.
423
+ - **Preserve row refusal details in import status records** — `@voltro/data-transfer`
424
+
425
+ Keep the bounded row refusal report in error messages and the first terminal import-status update. Polling clients receive concrete row reasons and counts instead of only the error tag, while typed error handling and wire schemas remain unchanged.
426
+ - **Inspect access discards sensitive drafts on permission withdrawal** — `@voltro/devtools-ui`
427
+
428
+ The shared inspect-access form discards unsaved credentials and endpoint/removal drafts when configure permission is withdrawn or a typed access/session refusal arrives. Restored access starts with a fresh form; late saves from the old form cannot clear a new draft or claim success. Transient read failures retain unfinished drafts. Typed write refusals use readable localized feedback.
429
+ - **Served app inspection endpoint setup** — `@voltro/devtools-ui`
430
+
431
+ Inspection access forms can expose a served-app base URL when the host supports endpoint editing. Hosts that own endpoint discovery retain their credential-only form. Invalid saves preserve drafts; fresh observations update untouched URL fields. Read and write credentials remain separate and saving confirms configuration, not connectivity.
432
+ - **Inspect credential validation guides corrections at the affected field** — `@voltro/devtools-ui`
433
+
434
+ Inspect credential forms focus and mark the affected field when a host supplies a field-specific validation error. Unknown save failures show write guidance, while rejected drafts remain available for correction and access revocation still clears sensitive inputs.
435
+ - **Inspect credential inputs wait until the browser form is ready** — `@voltro/devtools-ui`
436
+
437
+ Server-rendered inspect credential forms keep endpoint, token, and removal controls disabled until browser handlers are ready. Early input can no longer disappear during hydration. The form exposes its preparing state to assistive technology; deliberate saves remain available once ready.
438
+ - **Data explorer drafts survive acknowledgements of the current query** — `@voltro/devtools-ui`
439
+
440
+ The data explorer retains an active record draft when the router acknowledges the same query. Changing the table, filter, search, sort or page still opens a fresh view. Reconnection and later external updates do not automatically replay writes.
441
+ - **Show readable inspection permission and session failures** — `@voltro/devtools-ui`
442
+
443
+ Show localized permission and session explanations in shared inspection sections and the migrations panel instead of rendering structured transport objects as `[object Object]`. Keep readable local error messages and provide clear recovery guidance without dumping unknown transport payloads.
444
+ - **Inspection views explain protected values** — `@voltro/devtools-ui`
445
+
446
+ Inspection tables and record details explain sensitive, server-only and encrypted mask markers instead of displaying transport JSON. Protected values have no editor or reference action and are omitted when copying a record. Ordinary JSON remains unchanged; column metadata preserves the three independent protection axes.
447
+ - **Inspection reconnects retain the last observed values** — `@voltro/devtools-ui`
448
+
449
+ The data explorer explains that disconnected live updates retain the last observed values until recovery. It no longer promises successful periodic snapshots while the connection is unavailable.
450
+ - **Stable identifiers across island hydration roots** — `@voltro/web`, `@voltro/cli`
451
+
452
+ Islands preserve React identifiers for labels, inputs and SVG references across server rendering and client hydration, including repeated instances and framework runtime wrappers. Nested islands share their hydrating parent's root. The independent-root context and hydration prefix add about 0.5 KB gzipped to the reference islands entry, which remains below 70 KB; its measured chunk budgets are updated accordingly.
453
+ - **Island previews preserve state in other development pages** — `@voltro/cli`
454
+
455
+ Opening or refreshing an islands preview no longer reloads unrelated development pages or discards their unsaved state. Identical generated entries retain their files; changed island entries update only the clients using them, while source edits continue to use normal hot updates.
456
+ - **ISR nonce refusals explain the same remedies in dev and production** — `@voltro/cli`
457
+
458
+ `voltro dev` and `voltro start` now give the same route-specific diagnostic when middleware supplies `cspNonce` for an ISR page. The shared refusal runs before serving cached ISR HTML; use `renderMode = 'ssr'` for per-request nonces or a hash-based CSP for ISR.
459
+ - **Keep RPC startup code off API-free production pages** — `@voltro/client`, `@voltro/web`
460
+
461
+ Production apps without configured APIs use shared browser bootstrap primitives without eagerly loading RPC transports or the form engine. API apps, development tools and enabled debug sessions load the full runtime before mounting. Loader queries load their existing reader on demand. Shared contexts, seeded stores, lookup errors and SSR hydration tree IDs remain consistent.
462
+ - **Start query reactions after workflow readiness** — `@voltro/cli`
463
+
464
+ Attach query-watching reactions after the workflow runtime is ready during development startup. The first delivery can start its workflow immediately without waiting for a later resync after an initialization failure.
465
+ - **Existing subscriptions refresh authentication and permissions before delivery** — `@voltro/protocol`, `@voltro/runtime`, `@voltro/plugin-rbac`
466
+
467
+ Live queries, event subscriptions and streams now rerun their original authentication chain and refresh role-derived permissions before delivering data. Revoked credentials, memberships or grants end existing subscriptions with a typed refusal. Computed queries, row filters and column access use refreshed authority; the original identity and tenant remain bound to the subscription.
468
+
469
+ Configured authentication and scope caches retain their documented invalidation windows. Independent delivery snapshots prevent concurrent refreshes from mixing subject metadata and permissions. No migration is required.
470
+ - **Live computed reads report failures and recover automatically** — `@voltro/runtime`
471
+
472
+ An already subscribed computed query now reports ordinary recomputation failures through the existing in-band error channel as a sanitized `QueryRecomputeFailed`. The client retains its last successful data alongside that error, so applications can distinguish stale data from a current result without exposing server details.
473
+
474
+ The runtime retries failed reads with exponential delays from one to thirty seconds. A successful retry sends a snapshot even when the value is unchanged, clearing the error without another source mutation or a page reload. Source changes can recheck sooner. Reads for one subscription are serialized and intervening changes are coalesced before delivery.
475
+
476
+ Unsubscribe and server shutdown cancel pending retries and suppress late results. Every retry uses the existing executor and its current access checks; typed access withdrawal remains terminal. Mutations and actions are not replayed.
477
+ - **Live queries withdraw access when credentials expire** — `@voltro/runtime`
478
+
479
+ Live row and computed queries now report `Unauthenticated` when their credential expires, so applications can withdraw protected views instead of retaining a silently completed subscription. The refusal remains isolated to the affected subscription.
480
+ - **Workflow permission checks refresh current caller authority** — `@voltro/protocol`, `@voltro/runtime`, `@voltro/cli`
481
+
482
+ `ctx.access.require(scope)` now refreshes bound authentication and permissions when its Effect executes, including repeated execution of the same guard. Durable workflows retain an identity-bound resolver, so later permission checks observe credential expiry, revocation and current grants. Authority-source failures abort the operation. These checks do not interrupt an already executing external operation or replace transactional authorization fences.
483
+ - **Reload middleware when its imported sources change** — `@voltro/cli`
484
+
485
+ Web development restarts when any transitive middleware value-import changes, including shared sources outside the web app and helpers inside src. Type-only imports do not trigger replacement.
486
+ - **Render service outages with an explicit HTTP status** — `@voltro/web`, `@voltro/cli`
487
+
488
+ Middleware can return responseStatus alongside responseHeaders, for example 503 with Retry-After. Dev and built start preserve the status on streamed SSR, buffered SSR and SPA shells. Non-200 ISR responses bypass the cache. Loader redirects and notFound retain their own status.
489
+ - **Named plugin instances pass RPC code generation** — `@voltro/cli`
490
+
491
+ RPC code generation accepts the `#` separator used by named plugin installations while preserving their wire names. Canonical and named instances generate distinct valid JavaScript identifiers. Malformed names and names that collide after identifier normalization are still refused before a client group is written.
492
+ - **Include transitive JavaScript imports in build reports** — `@voltro/cli`
493
+
494
+ Include transitive static JavaScript imports in build reports without relying on preload hints, retaining CDN asset prefixes and identifying older artifacts without a recorded graph.
495
+ - **Outgoing webhook storage is declared at boot** — `@voltro/cli`, `@voltro/devtools-ui`
496
+
497
+ Apps that declare `@voltro/plugin-webhooks` in their own package manifest now include the webhook framework tables in their schema even when they only have outgoing `*.event.ts` declarations. Previously the feature detector only recognized incoming `*.webhook.tsx` files, leaving outgoing delivery storage unavailable.
498
+
499
+ Dev, build/serve, database planning/apply and migrations use the same manifest declaration. Workspace package availability alone does not enable storage in an unrelated event app. Signing secrets remain encrypted and require the configured field-encryption key in production.
500
+
501
+ All four canonical webhook tables are now included in the shared framework schema: targets, deliveries, rate windows, and event statistics. This also removes the stale event-statistics assembly exception; plugin discovery and CLI schema generation agree.
502
+
503
+ Dashboard target creation can now carry an explicit application tenant ID through shared UI, Cloud and native Inspect. The form requires the selection and keeps it on failures; native tenant refusals return a tenant field error. The transport field is additive and optional for existing callers; tenant-table constraints are unchanged.
504
+
505
+ Webhook snapshots normalize both native Date objects and serialized SQL timestamps to ISO strings. The regression uses real stored rows in both representations and still excludes signing material and payloads.
506
+
507
+ Webhook Inspect activity uses the canonical typed equality predicate, so delivery history is scoped to its event in native SQL stores as well as memory. Snapshot reads now provide complete query descriptors instead of bypassing descriptor type checking.
508
+ - **Plain storage keys isolate configured instances** — `@voltro/plugin-storage`
509
+
510
+ Separate new plain object keys by configured storage instance and logical bucket while preserving tenant prefixes and stored reference keys. Keep other instances’ existing shared-key references in physical deletion counts, preventing deletion of their still-referenced bytes on a shared backend. No user-authored API change is required; low-level service construction can supply the canonical storageInstance explicitly. Durable shared-generation and independent-provider existing-key reconciliation remain incomplete.
511
+ - **Preloaded subscriptions follow confirmed initial authority** — `@voltro/client`
512
+
513
+ Prevent preloaded subscription hooks from reapplying old SSR values or failure markers after an identity-changing reconnect or whole-cache resnapshot. New reads and remounted hooks wait for their own snapshot; ordinary socket recovery and same-subject token refresh retain the existing cache behavior. Apps must still gate workspace changes on a matching server context.
514
+ - **Preserve destination storage catalogue identity during logical transfers** — `@voltro/data-transfer`
515
+
516
+ Logical data exports omit the deployment's storage reference catalogue identity, and imports preserve the destination's identity even when an older or explicit-table bundle contains a foreign marker. Native disaster-recovery backup and restore continue to preserve the saved marker.
517
+ - **Query results recheck current authority at completion** — `@voltro/runtime`
518
+
519
+ Computed first snapshots and recomputations, descriptor subscription snapshots and deltas, and one-shot REST reads recheck current authentication and declared guards after awaited work. Revocation during a handler or store read discards the completed result and returns a typed refusal. Existing read-start checks remain in place; configured authentication and scope-cache windows still apply.
520
+
521
+ Existing guards are reused. No public API or user-authored source change is required. Guard callbacks remain read-only and may run at both read boundaries.
522
+ - **Invalidate returned database queries through declared sources** — `@voltro/runtime`, `@voltro/database`
523
+
524
+ Reactive queries that return database builders now retain their declared `source` dependencies alongside SQL dependencies. Authority-table changes recheck subscription guards and reread the finalized descriptor without waiting for a result-table write. Explicit sources invalidate independently of projected columns and row predicates; unchanged authorized results still suppress redundant deltas.
525
+
526
+ `QueryDescriptor.dependentTables` carries additional invalidation metadata without adding SQL joins, predicates or tenant access. Computed queries continue to rerun their executors; returned database descriptors continue to produce row snapshots and deltas.
527
+ - **Keep authentication prefix conflict warnings readable** — `@voltro/cli`
528
+
529
+ Authentication strategy prefix conflict warnings retain the conflicting prefix, strategy names and corrective guidance under the default credential redaction policy. Credential values remain redacted.
530
+ - **Redis read-your-writes receives broadcasts during subscription acknowledgement** — `@voltro/runtime`
531
+
532
+ The Redis RYW mirror installs its message listener before issuing SUBSCRIBE. This retains a peer's first broadcast if Redis delivers it before the local subscription promise settles. Channel and sender filtering remain unchanged.
533
+ - **Reference cleanup boots alongside application row filters** — `@voltro/cli`
534
+
535
+ `voltro dev` and `voltro serve` initialize reference cleanup with an explicit internal row scope, so registering application row filters no longer aborts boot. Cleanup can repair hidden orphaned rows while retaining its reference and tenant constraints; application callers keep their normal row filters.
536
+ - **Validate release artifact metadata before persistence** — `@voltro/plugin-releases`
537
+
538
+ Validate required release artifact metadata before persistence and treat stored blank signatures as unsigned in release lists, promotion checks, and Tauri feeds.
539
+ - **Fence artifact attachment to the current release target** — `@voltro/plugin-releases`
540
+
541
+ Add an optional appPrefix constraint to release artifact uploads for server adapters that delegate an authenticated app namespace. Claim exact target identity with its revision, reread it under the acquired fence, and lock the current release association before committing artifact and audit metadata. A changed association or target identity refuses without partial metadata changes.
542
+ - **Validate release file destinations before Storage writes** — `@voltro/plugin-releases`, `@voltro/cli`
543
+
544
+ # Release upload destination admission
545
+
546
+ Release file uploads now validate the destination before requesting Storage tickets or transferring bytes. The shared preparation query checks release ownership, app, version and explicit target revision; final metadata remains constrained to the resolved app and version. Cloud release-bound tickets use the same project-scoped preparation, while standalone project Storage uploads remain supported.
547
+
548
+ Deploy the updated API before using the updated file-upload CLI. Custom publish facades must expose the `prepare-upload` management action and preserve its destination constraints. This change does not provide transfer reservation, durable retries or orphan cleanup.
549
+ - **Request tests expose byte-stream response bodies** — `@voltro/testing`
550
+
551
+ `makeTestApp` consumes finite byte streams and exposes their exact `bytes` and decoded `text`, retaining the streaming marker. SSE responses remain unconsumed.
552
+ - **Handler defects preserve sibling live queries** — `@voltro/runtime`
553
+
554
+ Unexpected RPC handler failures now return a sanitized, request-correlated failure on WebSocket and HTTP transports. Other live queries on the connection continue receiving updates, so a deliberate retry after a failed write does not leave existing views frozen. Defect logging includes the request identifier; protocol defects remain connection-wide, and failed writes are not replayed automatically.
555
+ - **Use the framework trace generator for REST rate limits** — `@voltro/plugin-ratelimit`
556
+
557
+ Hand-authored REST rate-limit checks use the shared framework trace-ID generator, including checks that refuse the route before its handler runs. The runtime dependency is included in production installations.
558
+ - **Reviewed migration plans refuse changes after lock waits** — `@voltro/cli`, `@voltro/database`
559
+
560
+ `voltro db apply --plan` checks the complete reviewed schema and ordered operations again under the migration lock, before executing the plan. Concurrent schema changes now refuse with exit 2 instead of silently introducing unreviewed operations. Programmatic `applyPlan` callers receive an execution or convergence phase in their replan callback, so review checks do not reject the expected post-write empty plan. Ordinary automatic migrations continue to replan against the current schema.
561
+ - **Reviewed migration plans retain their exact operations and risk summary** — `@voltro/cli`
562
+
563
+ `voltro db apply --plan` now checks the complete ordered operations and risk summary against the current plan before applying schema changes. Changed review contents refuse even when both schema fingerprints still match. JSON object-key order remains irrelevant.
564
+
565
+ The online index threshold is preserved during replanning under the migration lock and the index phase after commit. Use the same planning options for plan and apply.
566
+ - **Keep verified credential lifetime local to each RPC** — `@voltro/runtime`, `@voltro/cli`
567
+
568
+ Capture verified credential expiry on the first RPC and keep it isolated between concurrent calls on the same connection. Add `withRpcAuthMiddleware` to compose authentication before metadata capture, preserve explicitly unbounded credentials, and refuse a reversed framework pair before running handlers. Custom auth implementations retain their existing lifetime fallback.
569
+ - **RPC output encoding defects name the procedure and request** — `@voltro/runtime`
570
+
571
+ Both RPC transports log Exit/Die encoding failures as well as protocol defects, with rpcTag and requestId when available. JSON-value failures explain that Schema.Unknown output must contain JSON values; declare date codecs or explicitly serialize database dates. Typed failures and output data remain unchanged.
572
+ - **Service callers can open context transactions** — `@voltro/cli`
573
+
574
+ An authenticated service admitted by a procedure can use `ctx.transaction` outside an existing mutation. The shared development and production context retains the same service identity when opening its internal transaction, instead of refusing an undecided synthetic procedure. Nested work still joins that transaction and callback failures roll back the complete unit. Other procedures keep enforcing their own service audience; this grants no human session or additional scopes.
575
+ - **Preserve SQL causes in migration recovery diagnostics** — `@voltro/database`
576
+
577
+ Migration failures retain their original SQL cause and the progress, history-write or operation-ledger cleanup diagnostic. Getter-only SQL errors no longer replace these recovery details with a message-assignment TypeError; receipt validation and operation-ledger retention remain enforced.
578
+ - **SQLite-family write results retain declared column names beside bigint values** — `@voltro/database`
579
+
580
+ Explicitly alias ordinary columns in SQLite-family bigint row projections. Native Turso write results now retain declared IDs, tenant fields and timestamps instead of quoted expression labels. This preserves insert-ignore results and prevents the first successful storage quota reservation from being charged twice.
581
+ - **Keep internationalization provider effects stable** — `@voltro/i18n`
582
+
583
+ Keep the default internationalization error handler stable across provider renders. Releasing the SSR hydration clock no longer changes the translator context solely because a new error-handler closure was created, avoiding repeated effect-driven actions with unchanged inputs. Missing-translation suppression and explicit error-handler overrides are preserved.
584
+ - **Storage catalogue pages use correct singular and plural counts** — `@voltro/devtools-ui`
585
+
586
+ Display one file or Datei correctly in combined catalogue page counts while retaining the existing per-catalogue pagination semantics.
587
+ - **Persisted storage references belong to their configured instance** — `@voltro/plugin-storage`
588
+
589
+ Default persisted references, grants and upload intents are scoped to their configured storage instance. Wrong-instance reads and management cannot resolve another instance’s reference. Grant creation refuses missing and foreign-instance references before inserting a grant. Tenant quota remains shared and bucket metadata is preserved.
590
+
591
+ Existing metadata requires an explicit ownership assignment after the additive schema migration; application startup refuses unassigned rows. The `assignStorageReferenceInstancesInTransaction` helper runs in an after-schema file migration with serving replicas stopped. It preserves reference and upload identities, claims, quota and provider bytes, and refuses conflicting assignments. Independent providers sharing durable object generations still require separate lifecycle isolation.
592
+ - **Storage tokens expire at their signed deadline** — `@voltro/plugin-storage`
593
+
594
+ Native signed read grants and upload, finalize, resumable and multipart tickets now reject the exact signed expiry second. A zero-second lifetime no longer permits an upload, and expired tokens receive no extra second of access. Approved owner, tenant and access-policy bindings are unchanged.
595
+ - **Storage streams refuse missing objects before download headers** — `@voltro/plugin-storage`
596
+
597
+ StorageService acquires provider streams before constructing download responses. Missing files and provider acquisition failures retain their typed errors instead of failing only when the body is consumed. Supported providers still stream bodies without buffering them; providers without streaming support retain the existing buffered fallback.
598
+ - **Subscription refusals preserve their JSON wire representation** — `@voltro/protocol`
599
+
600
+ Subscription error frames preserve the JSON representation of tagged error instances before strict wire encoding. Live permission refusals retain their tags and fields instead of becoming JSON serialization defects. Non-serializable failures remain rejected.
601
+ - **Terminal subscription refusals remain visible after a snapshot** — `@voltro/client`
602
+
603
+ Queries retain their last valid data while exposing terminal handler or protocol failures through `error`, so an ended subscription is not silently presented as current. Refreshing the same query preserves its refusal until a successful delivery; transport interruption recovery and authentication identity resets keep their existing boundaries.
604
+ - **Keep component test recovery hooks consistent with the client** — `@voltro/testing`
605
+
606
+ The component test client withdraws preload seeds after a whole-cache refresh, including remounts, while retaining seeds across ordinary controlled transport changes. Visible error subscriptions, server health snapshots and action readiness use the controlled recovery surface. Disconnected actions fail before their handler starts; the harness does not automatically replay transport failures.
607
+ - **Recover client uploads with stable transfer identity** — `@voltro/client`
608
+
609
+ Retain the advertised native through-app upload operation across automatic retries. An optional caller-selected operationId supports recovery after a lost first mint acknowledgement or an explicit later UI retry with the same file and metadata. Reject a shared explicit identity for a multi-file batch before dispatch. Custom stores and other upload transports retain their separate contracts.
610
+ - **Through-app upload tickets resume one durable transfer** — `@voltro/plugin-storage`
611
+
612
+ Through-app upload tickets now use the native object operation when the application's DataStore and default metadata stores are bound. Replaying an issued ticket resumes one reference, keeps unfinished references out of listings, and recovers a retained intent after provider failure. Ordinary ticket responses expose the optional operation ID; supplying it with the same metadata in a fresh authorized request renews an expired ticket without another reference. Changed content under the same operation returns HTTP 409; upload and resumable responses retain declared provider error statuses. Custom metadata stores do not advertise native operation support.
613
+ - **Schedule initial SSR hydration as a React transition** — `@voltro/web`
614
+
615
+ Initial full-page SSR hydration uses React's transition scheduling while retaining server markup and React's first-interaction delivery. API/bootstrap initialization still completes before root creation; fresh client mounts and island strategies retain their existing paths.
616
+ - **Install component animation variables with their source** — `@voltro/cli`
617
+
618
+ `voltro ui add` and `voltro ui update` install component `cssVars` and CSS rules in one attributed, tracked local stylesheet. Tailwind animation utilities keep their delivered definitions; edited stylesheets retain the existing update protection. Unsafe CSS and remote resources remain refused before writes.
619
+ - **Preserve installed utilities in Git-tracked apps** — `@voltro/cli`
620
+
621
+ UI installation explicitly registers app sources with Tailwind so component utilities survive production builds after committing the project to Git.
622
+ - **Install exported theme geometry and local display fonts** — `@voltro/cli`
623
+
624
+ Install shared themes with exported geometry and component rules alongside both color modes. Validate the CSS before writing, keep local font imports before the rules, and retain exact Fontsource package pins and complete OFL licenses. Remote resources, escaping imports and unlicensed generated themes remain refused. Theme updates preserve edited stylesheets.
625
+ - **Keep the UI installer toolchain out of server artifacts** — `@voltro/cli`
626
+
627
+ Precompiled API and web servers keep the UI installer's TypeScript AST toolchain external. Source installation still uses the installed CLI dependencies; serving does not carry or load the compiler.
628
+ - **Keep UI installation React and renderer versions aligned** — `@voltro/cli`
629
+
630
+ When UI source pins React or React DOM, keep the application's existing counterpart on the same exact version, including the patch. Preserve its dependency group and refuse conflicting explicit registry pins before writing files. A renderer absent from the application is not added implicitly.
631
+ - **Accept valid dotted npm names in UI registry dependencies** — `@voltro/cli`
632
+
633
+ Allow valid dotted and underscored npm package names in Voltro UI registry dependencies, including highlight.js. Exact version pins and validation of unsafe names, URLs and filesystem paths remain required before installation writes files.
634
+ - **Apply selected UI themes after their base styles** — `@voltro/cli`
635
+
636
+ Keep tracked UI stylesheet imports in dependency order when installing a custom theme after Signal. The selected theme overrides its base palette while authored rules, unrelated imports and conditional imports remain intact. Repeated installation does not duplicate tracked imports.
637
+ - **Unchanged subscriptions confirm reconnect recovery** — `@voltro/runtime`, `@voltro/web`
638
+
639
+ A reconnect with no missed deltas now receives a fresh snapshot instead of a silent subscription adoption. This lets the client confirm that unchanged live queries have recovered and keeps subsequent updates live. Nonempty retained replays continue to deliver their missed deltas; existing authorization and tenant checks remain in place. No migration is required.
640
+
641
+ Browser recovery now stays in place in development as well as production. The development-only automatic page reload based on web-origin reachability has been removed: an API outage must not discard an open form's unsaved state.
642
+ - **Preserve creation metadata in default audited upserts** — `@voltro/runtime`
643
+
644
+ Default `upsert` and `upsertWithOutcome` preserve createdAt and createdBy on audited rows while stamping updatedAt and updatedBy. Insert defaults no longer leak into the conflict update projection. Explicit update lists, callbacks and updateValues remain deliberate overrides.
645
+ - **Preserve vendored source attribution in published packages** — `@voltro/ui-shadcn`
646
+
647
+ Package notices now include vendored source attribution from the package and its runtime dependencies. The styled UI kit ships the complete shadcn/ui MIT copyright and license separately from the framework license, alongside its source and build output. The publish stager retains these notices for consumers.
648
+ - **Audit hashes protect impersonation and stable row identity** — `@voltro/plugin-audit`
649
+
650
+ New audit entries use hash format 2, covering first-class impersonation, the derived scope key and pre-minted stable row identity. The nullable format column preserves verification of historical entries without rewriting their hashes; legacy coverage is counted separately. Unknown or downgraded markers fail verification. Apply the normal reviewed schema migration before production serving.
651
+ - **Require patched Vite for development and generated SDK builds** — `@voltro/cli`
652
+
653
+ The development toolchain and generated TypeScript SDK packages require Vite 8.3.3 or newer in the Vite 8 line, closing three launch-editor security advisories, including command injection on Windows (GHSA-587h-7wmj-h5pm, GHSA-698v-4r3x-3vcv and GHSA-r825-w8mm-5pxw).
654
+ - **Replace stale development module graphs after closing the live server** — `@voltro/cli`
655
+
656
+ API surface edits close the web server and optimizer before clearing dependency caches and starting a fresh process. Concurrent edits coalesce; failed shutdown or cache reset retries before failing visibly. Local replica publications use unique atomic temporary files.
657
+ - **Start workflow lease windows at the first engine dispatch** — `@voltro/workflow`
658
+
659
+ Workflow reservations retain their original finite lease duration when an ordinary or explicitly recovered start waits before engine dispatch. The first dispatch atomically moves that deadline forward using a fresh clock after execution-key preparation, so acknowledging a newly running start does not immediately free an already-expired slot. Later dispatch attempts, recovery-command replay and late acknowledgements do not renew the lease; normal finite crash-backstop expiry still applies after acknowledgement. Missing, bound, released or invalid reservation evidence refuses the first dispatch before engine I/O.
660
+ - **Record workflow authority refusal before application execution** — `@voltro/workflow`, `@voltro/runtime`, `@voltro/cli`
661
+
662
+ Development and production workflow hosts now record pre-body authority and row-filter refusals in the starter's remembered resident store. Engine failure and run history agree after credential revocation. The shared recording primitive uses existing transactional delivery and generation fences, terminal events, failure handoffs and lease cleanup without constructing an application context or running workflow code. Completed, cancelled and foreign-caller runs remain protected. Missing caller identities cannot allocate a tenant-owned run; storage errors fail visibly.
663
+ - **Waiting workflow starts preserve unchanged queue rows** — `@voltro/workflow`
664
+
665
+ Stop timestamp-only pending-row updates and change events when concurrency, singleton or pause conditions remain unchanged. Real deadline changes and durable arrival, retry, cancellation and admission transitions remain intact; coordinated polling continues to reconsider capacity.
666
+ - **Workflow inspection counts unknown acceptance as held capacity** — `@voltro/workflow`, `@voltro/cli`
667
+
668
+ Use the same lease predicate for admission and Flow inspection so an unreleased reservation with no execution acknowledgement remains visibly held after its timestamp expires. The inspector no longer reports spare capacity while those reservations block the pool.
669
+
670
+ ### Internal (no consumer-facing effect)
671
+
672
+ - **Agent-flow run status union order in the API report** — `@voltro/plugin-ai-flows`
673
+
674
+ The API report lists the members of the run `status` union in a different order. The members are the same seven literals; no type changed.
675
+ - **Resolve the audited search SDK redirect client to its security patch** — `@voltro/plugin-search`
676
+
677
+ Resolve the workspace's optional search SDK redirect client to `follow-redirects` 1.16.1 or a later 1.x patch, retaining the major-version cap and an explicit security-patch cooldown exception. The dependency audit covers credential-header stripping fixes. This workspace resolution does not rewrite independently managed application lockfiles.
678
+ - **Reuse an identical production bundle within its integration suite** — `@voltro/cli`
679
+
680
+ Build the relocated HTTP and tracing probe once per test run while preserving separate deployment directories, processes, environments and assertions for every case.
681
+ - **Durable signal coverage before wait registration** — `@voltro/workflow`
682
+
683
+ Exercise the real workflow engine when a notification arrives after body entry and before a suspending wait registers.
684
+ - **Fixture typechecks regenerate their RPC groups first** — `@voltro/cli`
685
+
686
+ API fixture typechecks run the existing code generator before the compiler. A cached sibling build cannot leave an ignored RPC group using a previous Effect major, and typecheck does not race that sibling build's regeneration.
687
+ - **Clarify internal router context boundaries** — `@voltro/web`
688
+
689
+ Keep router context plumbing separate from the application-facing routing hooks.
690
+ - **Kernel schema fixture includes draft and revision reference stages** — `@voltro/cms`
691
+
692
+ Advance the schema fixture version after reconciling the existing kernel test with staged references, revision identity columns and scoped reference indexes. Keep the existing native bulk-delivery test aligned with the two authorization fences around a shared read. Runtime schema, authorization and migration behavior are unchanged.
693
+ - **Use dependency-free ULID generation** — `@voltro/database`
694
+
695
+ ULID generation uses the maintained `ulid` package. The `ulidx` and `layerr` dependency chain is removed; the 26-character Crockford-base32 ID format, timestamp encoding and cryptographically secure randomness remain unchanged.
696
+ - **Measure web reference budgets across transitive static imports** — `@voltro/web`
697
+
698
+ Measure the web reference budget through transitive static ESM imports as well as preload hints, with cycle/re-export regression coverage and stricter retained ceilings.
699
+ - **Keep full test coverage while reducing pipeline overhead** — `@voltro/build`, `@voltro/cli`, `@voltro/runtime`, `@voltro/plugin-storage`
700
+
701
+ Parallelize cold builds and independent checks, verify transferred artifacts, balance exhaustive CLI test groups, and retire exclusive test services after their consumers finish. Reuse identical fixture builds and source dumps within a suite, observe process termination directly, and preserve diagnostic failures.
702
+ - **Preserve checked declaration inference** — `@voltro/build`
703
+
704
+ Keep full checking in the declaration emitter to preserve writable inferred return types. Retain native fail-fast validation and reuse checking only in API Extractor; add a consumer regression against the built flow executor.
705
+
706
+ ---
707
+
42
708
  ## [0.85.0] — 2026-10-10
43
709
 
44
710
  ### ⚠ BREAKING