diff --git a/demos/wasi.tape b/demos/wasi.tape index 2fd5bd6..bbd68a5 100644 --- a/demos/wasi.tape +++ b/demos/wasi.tape @@ -33,7 +33,7 @@ Enter Sleep 500ms Show -Type "wago add wago-org/wasi" +Type "wago add github.com/wago-org/wasi" Sleep 240ms Enter Sleep 7s diff --git a/guides/embed/imports-and-artifacts.md b/guides/embed/imports-and-artifacts.md index 275af76..f661b4a 100644 --- a/guides/embed/imports-and-artifacts.md +++ b/guides/embed/imports-and-artifacts.md @@ -64,4 +64,7 @@ if err := rt.Close(); err != nil { } ``` -`Close` is idempotent. Runtime close stops plugins and internal services, but direct instances remain caller-owned. +`Close` is idempotent. Closing explicitly keeps error ownership local. Runtime +close is also a final safety boundary: it closes and drains every still-live +runtime-created instance before stopping plugins. A retained instance handle is +closed afterward, and calling `Close` on it again is safe. diff --git a/guides/host-functions/authority-and-references.md b/guides/host-functions/authority-and-references.md index 700aa2e..127111b 100644 --- a/guides/host-functions/authority-and-references.md +++ b/guides/host-functions/authority-and-references.md @@ -28,8 +28,14 @@ Runtime `Policy` controls guest capabilities and coarse declared resource limits `HostModule` represents one active synchronous call. Do not store it, send it to another goroutine, or use it as a long-lived instance handle. -Plugins with the required privileged capability can resolve the exact caller while the callback is active. Forged, expired, and cross-runtime values fail closed. +Plugins that separately receive `host.caller.identify` can resolve an opaque, +comparable instance identity while the callback is active. The identity grants +no invoke, close, memory, export, or management operation. Forged, expired, and +cross-runtime `HostModule` values fail closed. ## Reusable host APIs -Use `WithImports` for an application-specific bridge. Package a shared namespace as a plugin so imports, capabilities, configuration, ordering, and cleanup are registered once and reviewed through the manager. +Use `WithImports` for an application-specific bridge. Package a shared namespace +as a plugin so exact import-module scope, guest capabilities, configuration, +dependencies, ordering, and cleanup are registered once and reviewed through +the manager. diff --git a/guides/plugins.md b/guides/plugins.md index eb81c80..f49bc94 100644 --- a/guides/plugins.md +++ b/guides/plugins.md @@ -1,10 +1,15 @@ --- -description: Add, review, update, lock, and publish Wago plugins without hiding their host authority. +description: Add, review, compose, update, lock, and publish Wago plugins without hiding their host authority. --- # Use plugins -Plugins provide host imports, lifecycle hooks, managed instances, module transforms, and compiler extensions. They are Go code compiled into your runtime, so review them like any other native dependency. +Plugins provide host imports, lifecycle integrations, managed instances, module transforms, compiler extensions, and typed services for other plugins. They are Go code compiled into your runtime, so review them like any other native dependency. + +Wago resolves explicit package dependencies and typed, major-versioned Contracts +as one graph. It reviews exact scoped Plugin Authorities before downloading or +building new code, then publishes the manifest, lock graph, and generated runtime +in one transaction. ## Pick a topic @@ -13,7 +18,7 @@ Plugins provide host imports, lifecycle hooks, managed instances, module transfo Add a plugin locally or globally and select it at run time. - Review privileged API access, guest capabilities, and reproducible state. + Review exact Authorities, dependency and Contract bindings, guest capabilities, and reproducible state. Check for updates, review changes, and reproduce the locked runtime. diff --git a/guides/plugins/grants-and-lockfiles.md b/guides/plugins/grants-and-lockfiles.md index 3ef9145..a0f97f5 100644 --- a/guides/plugins/grants-and-lockfiles.md +++ b/guides/plugins/grants-and-lockfiles.md @@ -1,61 +1,140 @@ --- -description: Review Wago plugin capabilities, guest authority, manifests, lockfiles, and resource budgets. +description: Review exact Wago Plugin Authorities, dependencies, typed Contracts, lockfiles, and resource limits. --- -# Review plugin grants and lockfiles +# Review Authorities, Contracts, and the lockfile -The manifest records what your project asks for. The lockfile records the exact plugin versions, capabilities, and runtime result you reviewed. +The manifest records direct project intent. The lockfile records the complete +resolution and every authority-bearing decision you reviewed. -## Manifest and lockfile +## Manifest and lock graph -`wago.json` records what the project wants: +`wago.json` contains canonical Plugin IDs and semantic-version ranges: ```json { - "$schema": "https://wago.sh/v0/schema.json", + "$schema": "https://wago.sh/v1/schema.json", "plugins": { - "wago-org/wasi": "^0.0.0" + "github.com/JairusSW/pool": "^0.1.0" } } ``` -`wago-lock.json` records what Wago resolved and what you approved: exact versions, required and granted capabilities, budgets, and opaque plugin configuration. +Pool requires Workers. Wago resolves Workers once as a transitive plugin and +records the exact Pool-to-Workers Contract binding in `wago-lock.json`. The lock +also contains source versions and Go checksums, release and definition digests, +published Authority Requests, reviewed Authority Grants, configuration, and the +complete dependency graph. Commit both files. Review lockfile changes like a native dependency update. -## Review grants +## Inspect before changing ```sh -wago plugin inspect wago-org/wasi -wago plugin grant wago-org/wasi +wago plugin tree +wago plugin list --json +wago plugin inspect github.com/JairusSW/pool +wago plugin inspect github.com/wago-org/workers ``` -Automation should name the decision: +JSON listing and inspection are side-effect-free. They read immutable +definitions and selections; they do not call plugin factories, registration, +or lifecycle code. + +## Review exact Authorities + +An Authority is one exact privileged Wago integration. Its dots group related +names for display only—parents, wildcards, descendants, and future Authorities +are never implied. + +| Authority | Authorizes | +|---|---| +| `host.import.define` | Define host functions in specifically granted import modules. | +| `host.caller.identify` | Resolve an opaque identity during a synchronous host call. | +| `host.arguments.read` | Read guest arguments owned by this Runtime. | +| `runtime.close.observe` | Observe logical runtime close. | +| `module.source.transform` | Replace source bytes before compilation. | +| `module.compile.observe` | Correlate source processing with compile success or failure through opaque identities. | +| `module.close.observe` | Observe logical close of a runtime-bound module. | +| `instance.instantiate.intercept` | Reject a request, or attach fallible identity-keyed state after initialization and before the start function. | +| `instance.instantiate.observe` | Observe successful or failed instantiation. | +| `instance.close.observe` | Observe exact-instance logical close. | +| `instance.invoke.intercept` | Inspect or reject a runtime-managed call. | +| `instance.invoke.observe` | Observe results and traps. | +| `instance.manage` | Create and own a bounded set of managed instances. | +| `core.module.compile` | Compile core modules for an execution-model plugin. | +| `core.instance.instantiate` | Instantiate and own core modules within reviewed limits. | +| `core.funcref.create` | Create typed host function references. | +| `compiler.type.define` | Define types in specifically granted namespaces. | +| `compiler.instruction.define` | Define instructions in specifically granted Wasm modules. | + +Every request has a `required` or `optional` mode, a human explanation, and any +scope Wago can enforce. A required Authority must have a grant, but you can +still narrow its modules or limits. An optional Authority may be denied +entirely. A plugin that cannot operate under the reviewed scope fails before the +plan commits. + +Interactive add and update show one consolidated review. For automation, name +each decision and scope explicitly rather than accepting a wildcard policy: ```sh -wago plugin add wago-org/wasi \ - --allow host.imports \ +wago add github.com/wago-org/workers \ + --allow instance.manage \ + --scopes '{"github.com/wago-org/workers":{"instance.manage":{"maxInstances":4,"maxMemoryBytes":268435456}}}' \ + --accept-contracts \ --no-input ``` -`--allow-all` and `--deny-all` are available, but an explicit capability list is easier to review. +`--scopes` is one strict JSON object keyed first by full Plugin ID and then by +exact Authority. Add and update may narrow direct or resolved transitive +plugins; `wago plugin grant ` may revise only that exact existing +selection. A scope override can never add a module, raise a requested limit, or +name an Authority the definition did not request. Instance-owning limits are +positive; zero does not mean unlimited. `maxMemoryBytes` bounds the aggregate +declared maximum across all live instances owned through that handle. -## Privileged plugin capabilities +## Typed cross-plugin Contracts -| Capability | Authorizes | -|---|---| -| `host.imports` | Host functions and active caller resolution | -| `host.environment` | Wago's narrow host environment | -| `module.compile` | Compile transforms and observations | -| `instance.lifecycle` | Instance creation and close hooks | -| `instance.invoke` | Runtime-managed call hooks | -| `runtime.lifecycle` | Runtime shutdown and cleanup | -| `instance.manage` | Restricted managed instances | +Plugins call each other through typed Contracts identified by a canonical ID +and positive incompatible major version. A consumer declares one of: + +- `required`: exactly one provider; +- `optional`: zero or one provider; or +- `many`: every selected provider in the exact reviewed binding order. + +The package requirement selects and links a provider package. The Contract +binds the interface among selected providers. Both edges participate in one +cycle-checked graph, and the exact binding is stored in the lockfile. -Some grants include budgets such as a live instance cap or per-instance declared memory limit. +Wago rejects missing required providers, incompatible majors, duplicate single +providers, altered locked bindings, and cycles before any factory runs. +Contract calls use callback leases rather than raw `Get` values. During close, +a consumer can still use its dependencies from its own `Stop`; before provider +teardown, Wago rejects new calls and waits for in-flight calls to finish. + +Compile observers receive an opaque digest of the final source bytes after all +transformers. The precompiled `Runtime.Module` path reports a zero digest because +the source is unavailable. `Module.Close` ends only the runtime-bound wrapper, +emits one close event, and leaves ownership of the caller-visible compiled +artifact with its caller. ## Plugin authority and guest authority -Plugin grants control access to privileged Wago APIs. Guest capabilities such as `fs.read` and `net.outbound` describe what the module may use. Runtime `Policy` applies the guest layer. +Plugin Authorities control access to privileged Wago integration handles. Guest +capabilities such as `fs.read` and `net.outbound` describe what a Wasm module may +use, and Runtime `Policy` applies that guest layer. + +Neither layer turns arbitrary plugin Go code into a sandbox. Plugins are native +open-source dependencies linked into the host and must still be audited as +such. + +## Verify locked state in CI + +```sh +wago plugin rebuild --locked +``` -Neither layer turns arbitrary plugin Go code into a sandbox. Plugins remain native open-source dependencies. +Locked rebuilding verifies reachability, dependency ranges, checksums, release +fingerprints, provider catalogs, definition digests, grants, configuration, +Contract bindings, target compatibility, and the dry-run Plugin Plan before it +reproduces the artifact without changing project state. diff --git a/guides/plugins/install-and-scope.md b/guides/plugins/install-and-scope.md index f4b781e..db2589a 100644 --- a/guides/plugins/install-and-scope.md +++ b/guides/plugins/install-and-scope.md @@ -10,17 +10,21 @@ Install plugins locally for one project or globally for your machine, then choos ```sh wago init --run -wago add wago-org/wasi +wago add github.com/wago-org/wasi ``` -`wago add` is the short form of `wago plugin add`. Wago resolves the package, asks you to review its capabilities, writes project state, and rebuilds the selected runtime. +`wago add` is the short form of `wago plugin add`. Wago resolves direct and +transitive packages, verifies typed Contract providers, and presents one review +of exact sources, scoped Authorities, and bindings. It stages the download, +provider catalog, generated runtime, and complete dry-run plan before atomically +replacing project state. A failure leaves the previous runtime usable. ## Local scope Local plugins belong to the nearest `wago.json`: ```sh -wago plugin add --local wago-org/wasi +wago plugin add --local github.com/wago-org/wasi ``` Use local scope for applications and repositories. The dependency and authority travel with the project. @@ -30,7 +34,7 @@ Use local scope for applications and repositories. The dependency and authority Global plugins are shared across your user account: ```sh -wago plugin add --global wago-org/wasi +wago plugin add --global github.com/wago-org/wasi ``` This works well for personal tools used across unrelated directories. @@ -46,14 +50,20 @@ wago run --bare --invoke fib fib.wasm 20 - `--local` uses the project plugin set. - `--global` uses the shared user-wide set. - `--bare` uses neither. -- `--plugin name,other` adds plugins for one command. -If a plugin becomes part of the application, add it to `wago.json` instead of leaving it in shell history. +Add plugins to `wago.json` before running so resolution, Authorities, and +Contract bindings remain reviewable and reproducible. ## Inspect the selection ```sh wago status wago plugin list -wago plugin inspect wago-org/wasi +wago plugin list --json +wago plugin tree +wago plugin inspect github.com/wago-org/wasi ``` + +`tree` shows why every transitive plugin was selected. JSON listing and +inspection report exact definitions, Authority Grants, Contract bindings, and +activation order without starting plugin code. diff --git a/guides/plugins/publish.md b/guides/plugins/publish.md index 3352adc..395ac8c 100644 --- a/guides/plugins/publish.md +++ b/guides/plugins/publish.md @@ -4,11 +4,11 @@ description: Initialize, review, authenticate, and publish an open-source Wago p # Publish a Wago plugin -Package a reusable Wago extension, preview exactly what will ship, then publish it to the public plugin registry. +Package a reusable Wago plugin, preview exactly what will ship, then publish it to the public plugin registry. Publishing requires a public GitHub repository and a Wago registry account. The dry run works before login. -## Create the manifest +## Scaffold the plugin ```sh wago init --plugin \ @@ -21,7 +21,16 @@ wago init --plugin \ --yes ``` -A publishable manifest points to public source and includes an SPDX license. Wago plugins are deliberately open source. +The scaffold creates a v1 manifest, one-method plugin, immutable +`PluginDefinition`, explicit `/register` catalog, canonical +`wago.providers.json`, and drift tests. A publishable manifest points to public source, includes an SPDX +license and structured author, and keeps discovery metadata under `package`. +Wago plugins are deliberately open source. + +Declare every privileged Wago integration as an exact Authority with a human +reason and enforceable scope. Declare package requirements separately from +typed, major-versioned Contracts. Provider catalogs return values from +`Providers()`; they never self-register from `init`. ## Authenticate @@ -30,11 +39,32 @@ wago auth login wago auth whoami ``` -## Preview and publish +## Snapshot, tag, and publish ```sh +wago plugin catalog +wago plugin catalog --check +git add wago.json wago.providers.json register +git commit -m "Prepare plugin v0.1.0" +git tag v0.1.0 +git push origin HEAD v0.1.0 wago plugin publish --dry-run --json wago plugin publish ``` -Publishing uses `wago.json` and Git `HEAD` by default. Flags can override the manifest, commit, release notes, category, and tags. +`wago plugin catalog` executes the current checkout's explicit catalog and +writes its canonical, digest-bearing snapshot. Commit that file before tagging; +`--check` is the CI-friendly drift gate. The provider artifact uses +`https://wago.sh/v1/providers.schema.json`. + +The publish dry run only prints the planned mutation. Actual publishing first +checks the local catalog against the committed snapshot, then downloads the +exact tagged Go module. Its `wago.json` package metadata and +`wago.providers.json` must match the local release, and its `h1:` checksum is +sent with the request. Local code runs only for the local drift check; Wago does +not execute code from the downloaded tag. + +The registry independently downloads that same exact module and checksum, reads +both artifacts without executing plugin code, and rejects any mismatch. +Consumers later review the stored immutable definitions before plugin code is +downloaded or built; linked definitions must match their reviewed digests. diff --git a/guides/plugins/update-and-rebuild.md b/guides/plugins/update-and-rebuild.md index f8e84f3..6074dea 100644 --- a/guides/plugins/update-and-rebuild.md +++ b/guides/plugins/update-and-rebuild.md @@ -17,7 +17,7 @@ This reports newer releases without changing the manifest, lockfile, or runtime. ## Update one plugin ```sh -wago plugin update wago-org/wasi +wago plugin update github.com/wago-org/wasi ``` Update the selected scope: @@ -26,7 +26,11 @@ Update the selected scope: wago plugin update ``` -Review the resulting `wago.json` and `wago-lock.json` diff before committing it. A version change can add native code or request new authority. +Review the resulting `wago.json` and `wago-lock.json` diff before committing it. +A version change can alter transitive resolution, native code, requested +Authorities, configuration schema, or Contract bindings. Wago re-prompts only +for new or widened authority; an existing grant is preserved only when it still +fits the new request. ## Rebuild from the lockfile @@ -34,7 +38,9 @@ Review the resulting `wago.json` and `wago-lock.json` diff before committing it. wago plugin rebuild ``` -This reproduces the selected plugin-enabled runtime from exact locked versions. +This reproduces the selected plugin-enabled runtime from exact locked versions, +checksums, release fingerprints, provider catalogs, definition digests, grants, +configuration, and Contract bindings. For a final prepared build: @@ -55,7 +61,14 @@ Use a networked preparation step to resolve and review changes, then use locked ## Remove a plugin ```sh -wago rm wago-org/wasi +wago rm github.com/wago-org/wasi ``` -This is the short form of `wago plugin remove`. +This is the short form of `wago plugin remove`. Removing a direct requirement +also prunes transitive plugins no longer reachable from another direct root. If +that changes an optional or `many` Contract binding, Wago asks you to review the +exact provider change. Non-interactive jobs must opt in explicitly: + +```sh +wago plugin remove github.com/wago-org/wasi --accept-contracts --no-input +``` diff --git a/guides/run/artifacts.md b/guides/run/artifacts.md index ba3a4e2..eeb5c64 100644 --- a/guides/run/artifacts.md +++ b/guides/run/artifacts.md @@ -51,7 +51,9 @@ wago compile --bare fib.wasm --invoke fib -o fib-bare - `--local` uses the nearest `wago.json`. - `--global` uses the user-wide plugin set. - `--bare` disables both sets. -- `--plugin name,other` adds plugins for this command. + +Add plugins to `wago.json` before building so the standalone artifact uses the +same reviewed and locked graph as the project. Preview standalone work before changing anything: diff --git a/guides/run/inspect-and-validate.md b/guides/run/inspect-and-validate.md index e35e737..566a55a 100644 --- a/guides/run/inspect-and-validate.md +++ b/guides/run/inspect-and-validate.md @@ -32,7 +32,7 @@ The module probably needs a plugin or application-supplied host functions. A WAS ```sh wago init --run -wago add wago-org/wasi +wago add github.com/wago-org/wasi ``` Read [Use plugins](/guides/plugins) before granting access to host resources. @@ -49,7 +49,7 @@ wago plugin list --global wago status ``` -Then run with `--local`, `--global`, or an explicit `--plugin` selection. +Then run with `--local` or `--global`, or add the plugin to `wago.json` first. diff --git a/reference/configuration/project-manifest.md b/reference/configuration/project-manifest.md index 16dfaf7..d24c110 100644 --- a/reference/configuration/project-manifest.md +++ b/reference/configuration/project-manifest.md @@ -8,7 +8,7 @@ description: Configure Wago runtime features, optimizations, workers, and plugin ```json { - "$schema": "https://wago.sh/v0/schema.json", + "$schema": "https://wago.sh/v1/schema.json", "settings": { "features": { "simd": true @@ -22,7 +22,7 @@ description: Configure Wago runtime features, optimizations, workers, and plugin } }, "plugins": { - "wago-org/wasi": "^0.0.0" + "github.com/wago-org/wasi": "^0.1.0" } } ``` @@ -67,12 +67,47 @@ The names match CLI switches such as `--no-inline`. Architecture-specific optimi ## Plugins and lockfile state -`plugins` maps GitHub-relative IDs to semantic-version constraints. Exact resolution, grants, budgets, and opaque plugin configuration belong in `wago-lock.json`. +`plugins` maps canonical Go module or package paths to semantic-version ranges. +Exact direct and transitive sources, checksums, release fingerprints, definition +digests, dependency edges, requested and granted Authorities, Contract bindings, +and opaque plugin configuration belong in `wago-lock.json`. + +Ranges support exact, comparator, caret, tilde, partial/x, hyphen, intersection, +and `||` union forms. Relative aliases are invalid: use +`github.com/wago-org/wasi`, not `wago-org/wasi`. Commit both files. Keep plugin configuration out of `settings`; it belongs to the plugin's reviewed lock entry. ## Publish metadata -When the manifest describes a publishable plugin, it can also contain module path, semantic version, display metadata, SPDX license, public repository, tags, authors, platform constraints, and subpackages. +When the manifest describes a publishable plugin, public metadata lives under a +`package` object: + +```json +{ + "$schema": "https://wago.sh/v1/schema.json", + "package": { + "module": "github.com/acme/wago-observability", + "version": "0.1.0", + "name": "Wago Observability", + "description": "Tracing and metrics for Wago runtimes.", + "license": "Apache-2.0", + "repository": "https://github.com/acme/wago-observability", + "authors": [ + { "name": "Example Maintainer", "github": "example" } + ] + } +} +``` + +Provider definitions, Authorities, configuration schemas, and Contracts are not +duplicated by hand in this file. Publishing obtains them from the module's +explicit `/register` catalog and stores their canonical digests beside the +release. + +The committed module-root `wago.providers.json` is the immutable catalog +snapshot. Generate it with `wago plugin catalog`, verify it in CI with +`wago plugin catalog --check`, and commit it before creating the release tag. +It uses `https://wago.sh/v1/providers.schema.json`. See [Publish a plugin](/guides/plugins/publish) for the complete workflow. diff --git a/troubleshooting/modules-and-calls.md b/troubleshooting/modules-and-calls.md index cb4843f..26316ee 100644 --- a/troubleshooting/modules-and-calls.md +++ b/troubleshooting/modules-and-calls.md @@ -37,7 +37,7 @@ For a local project: ```sh wago init --run -wago add wago-org/wasi +wago add github.com/wago-org/wasi wago plugin list ``` diff --git a/troubleshooting/plugins-and-builds.md b/troubleshooting/plugins-and-builds.md index 266c3a1..d151047 100644 --- a/troubleshooting/plugins-and-builds.md +++ b/troubleshooting/plugins-and-builds.md @@ -1,5 +1,5 @@ --- -description: Diagnose Wago plugin resolution, capability grants, lockfiles, offline mode, and standalone builds. +description: Diagnose Wago plugin resolution, Authority Grants, Contract bindings, lockfiles, offline mode, and standalone builds. --- # Fix plugin resolution and standalone builds @@ -11,15 +11,24 @@ Inspect the selected scope and resolved plugin graph before changing grants, loc ```sh wago status wago plugin tree -wago plugin inspect +wago plugin list --json +wago plugin inspect github.com/wago-org/wasi +wago plugin rebuild --locked ``` Then identify the failing stage: +- If `wago.providers.json` is missing or stale, run `wago plugin catalog`, + inspect the diff, and commit it before tagging. Use + `wago plugin catalog --check` in CI. +- If publish reports an exact-source mismatch, the tagged module's + `wago.json` or `wago.providers.json` differs from the local release. Move the + version forward and create a new tag after committing both artifacts; do not + reuse a published Go module version. - `wago plugin outdated` checks for newer releases. -- `wago plugin grant wago-org/wasi` edits authority. +- `wago plugin grant github.com/wago-org/wasi` edits reviewed Authority scope. - `wago plugin rebuild` reproduces locked versions. -- `wago plugin update wago-org/wasi` changes resolution and rebuilds. +- `wago plugin update github.com/wago-org/wasi` changes resolution and rebuilds. Use `--verbose` when the underlying Go build diagnostic matters. @@ -33,6 +42,49 @@ wago plugin update --dry-run --json Review and commit the result, then retry locked mode. +Locked mode can also fail when a transitive edge, source checksum, release +fingerprint, provider catalog, definition digest, Authority Grant, configuration, +or Contract binding no longer matches the committed graph. The locked rebuild +identifies the exact field; do not hand-edit a digest or binding to silence it. + +## Dependency resolution fails + +The plan reports every constraint and the parent that contributed it. If no +global solution exists, update or remove the conflicting direct requirement +rather than forcing one transitive version. Wago backtracks across available +releases and prefers the highest deterministic complete solution, so a conflict +means the published ranges genuinely cannot be satisfied together. + +A dependency or Contract cycle is invalid even when every individual range is +compatible. Break the package edge or move the shared behavior behind a lower +level Contract provider. + +## Contract binding fails + +Check the consumer's Contract ID, major, and mode against the selected provider: + +```sh +wago plugin list --json +``` + +Required and optional Contracts accept at most one provider; `many` accepts the +complete deterministic provider list. A different major is deliberately +incompatible. Locked mode never silently chooses a replacement provider. + +## An Authority is denied + +Inspect the published request and current grant: + +```sh +wago plugin inspect github.com/wago-org/workers +wago plugin grant github.com/wago-org/workers +``` + +A required Authority must remain present, but its scope can be narrowed. If the +plugin needs a withheld module or a larger minimum resource budget, registration +fails before commit and your previous runtime stays active. A grant cannot widen +the publisher's request. + ## Offline mode fails A required module or artifact is missing locally. Fetch it during an intentional networked preparation step, then run the final build offline. @@ -50,6 +102,7 @@ Check that: - `_start` exists or `--invoke` names a real export; - the target is Darwin, Linux, or Windows on AMD64 or ARM64; - required plugins are selected; +- every required Contract has its locked provider; - dependencies exist locally when offline mode is enabled; - plugins support the target.