feat: bind Host interfaces to scope Object lifetimes

Register explicit scope/name coordinates independently of Definition type. Require provider-attested current scope snapshots for fetch and dispatch, compare optional scope_ref at membership precedence, and retain the same Descriptor through result validation.

Migrate FS pinned-root boundaries and public self-scope example; document provider atomicity/lifecycle and root-only FS support. Add lifecycle, ref, replacement-race, root-lineage and compile-time exposure regressions.

Validation: cargo fmt --all --check; git diff --check; cargo check --workspace --all-targets; cargo test --workspace --all-targets and --doc (232 passing test-harness cases including doctests); nix develop --command cargo clippy --workspace --all-targets -- -D warnings; RUSTDOCFLAGS=-Dwarnings cargo doc --workspace --no-deps. Narrow wip-host suite also passed.
This commit is contained in:
2026-10-08 03:18:13 +09:00
parent 8ecc307fc9
commit 755e6aeb88
15 changed files with 1585 additions and 248 deletions
+35 -10
View File
@@ -26,9 +26,13 @@ For an external backend/composition:
protected state. Implement `FilesystemBackend` to resolve one connected
`ResolvedEntry<Entry>` (root-to-parent ancestry plus pinned target), enumerate
bounded children, and execute against that already-resolved lineage.
2. Register generated `#[wip_interface::interface]` definitions using the existing
`wip_host::InterfaceRegistry`. `DefaultInterfaces::register` optionally supplies
reusable built-in tokens; using those tokens does not force their publication.
2. Create `wip_host::Scope::new("/")` for the deployment-pinned root, then
register generated definitions with `registry.register(&scope, name,
Definition, validator)`. `DefaultInterfaces::register(&mut registry, &scope)`
optionally supplies reusable built-in tokens named `file.read`,
`symlink.inspect`, and `file.write`; tokens do not force publication. The
current engine binds only the root scope and fails closed for non-root
registrations; broader FS scope semantics remain follow-up work.
3. Implement `Composition<Entry>` on a local type. Its local Object wraps the entry
and implements both `WipObject` and the chosen generated traits, avoiding orphan
rules. `PublishedObject::expose` proves each implementation at compile time.
@@ -61,7 +65,26 @@ from one connected backend traversal/snapshot, not independent path-prefix
resolutions. A root target has no ancestors; other targets retain the root first,
then intermediate parent containers. This is backend-private context, never wire
metadata. Backend `resolve` and `execute` signatures both carry this type;
compositions still receive only the exact scoped target `Entry`.
compositions receive exact retained entries, including publication of the root
scope Object while another target is executing, never independent raw-path
lookups. Root publication must be deterministic and side-effect-free.
Every lineage must retain the same deployment-pinned root Object. Replacing that
Object requires a new projection and fresh `Scope`, not reuse of registrations
at the same path. The engine constructs `ScopeObservation` from the published
root Object's metadata using the refreshed retained root capability **inside**
`FilesystemBackend::execute`, then attaches it with `PublishedObject::bind_scope`.
It never independently looks up the raw configured root path. Root Objects need
not expose any interfaces. Calls check both the private lifetime and optional
`scope_ref`; normal root state updates do not retire the lifetime.
`with_object` (including fetch) and individual tree Object publications also
enter this backend boundary. Generic read callbacks use a `NotStarted` attempt
as an adapter to the existing execution API; no typed operation runs and no
commit is implied. Tree observations are bounded traversals, not one global tree
transaction. Fetch resolves the visible scope Object through the provider and
returns its ref, Descriptor and Interface validator together; retained registry
artifacts alone never establish publication.
`FilesystemBackend::execute` must validate ancestor membership/identity and
refresh **all** lineage state/validators inside its transaction or lock before
@@ -196,14 +219,16 @@ curl -sS -X POST http://127.0.0.1:8080/wip/v1/observe \
```
A regular-file observation returns a structured read interface reference and an
object validator. Built-in legacy registrations use scope `/` and copy the opaque
registration string verbatim into `name`; they do not emit `scope_ref`. Copy the
complete reference from the observation to retrieve that descriptor:
object validator. Built-ins explicitly use scope `/` and the local names
`file.read`, `symlink.inspect`, and `file.write`. The Linux root does not issue an
Object ref, so fetch omits `scope_ref`; its private publication lifetime still
binds fetch and call to the pinned deployment root. Copy the complete reference
from the observation to retrieve that descriptor:
```console
curl -sS -X POST http://127.0.0.1:8080/wip/v1/fetch_interface \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
--data '{"interface":{"scope":"/","name":"<read-interface-name-from-observation>"}}'
--data '{"interface":{"scope":"/","name":"file.read"}}'
```
Then call a bounded range read:
@@ -213,7 +238,7 @@ curl -sS -X POST http://127.0.0.1:8080/wip/v1/call_operation \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
--data '{
"target":{"path":"/notes.txt","validator":"<base64-validator>"},
"interface":{"reference":{"scope":"/","name":"<read-interface-name>"}},
"interface":{"reference":{"scope":"/","name":"file.read"}},
"operation":"read",
"arguments":{"offset":0,"length":4096}
}'
@@ -227,7 +252,7 @@ curl -sS -X POST http://127.0.0.1:8080/wip/v1/call_operation \
-H 'Content-Type: application/json' -H 'Accept: application/json' \
--data '{
"target":{"path":"/notes.txt","validator":"<base64-validator>"},
"interface":{"reference":{"scope":"/","name":"<write-interface-name>"}},
"interface":{"reference":{"scope":"/","name":"file.write"}},
"operation":"replace",
"arguments":{"contents":"dXBkYXRlZA=="}
}'