Merge develop into T-731 source and align scoped authorization logging fixture

This commit is contained in:
2026-10-10 14:20:32 +09:00
29 changed files with 3803 additions and 261 deletions
+21 -4
View File
@@ -31,10 +31,25 @@ The implementation uses the published **WIP 0.2.0** Client, HTTP, Protocol and o
A WIP Worker exposes exactly these generic LLM tools instead of exposing every enabled ordinary tool twice:
- `Tree(path, depth)`: retrieve the full indexable range within depth 0..8, or report incomplete/loading/failed/limited coverage as an error. Children at the requested boundary remain unobserved (null), not empty. Cached nonindexable paths are never included by prefix scanning Known Space.
- `Inspect(path)`: directly acquire an Object, then every published Interface, and return complete official Object/Interface signatures in declaration order. It requires no prior Tree or manual descriptor fetching. The path is explicit JSON envelope context outside the path-free signature. Summaries are complete; runtime metadata and documentation details are not appended to signatures.
- `Inspect(path)`: acquire and display exactly the selected entity. An Object path returns only its official Object signature and ordered Interface references (each with an explicit inspection path); it does not fetch Interface descriptors. An absolute `scope::name` Interface address returns only that Interface's complete official signature. Neither form requires a prior Tree or Inspect. The path is explicit JSON envelope context outside the path-free signature. Summaries are complete; runtime metadata and documentation details are not appended to signatures.
- `Invoke(path, interface, operation, arguments)`: use a structured `{scope, name}` reference and named argument record. The Client owns validators and observed scope_ref. Missing/stale/failed observations are recovered with at most one pre-dispatch retrieval per subject. A dispatched operation is never automatically retried.
Tree and Inspect accept explicit `refresh: true` for blocked observations. An ensure API returning None is never itself readiness evidence: freshness, complete edge coverage and retained data are checked. Loading and capacity pressure are reported rather than superseded or busy-looped.
Tree and Inspect accept explicit `refresh: true` for blocked observations. Inspect refreshes only the selected Object or Interface, not referenced entities. An ensure API returning None is never itself readiness evidence: freshness, complete edge coverage and retained data are checked. Loading and capacity pressure are reported rather than superseded or busy-looped.
The Yoi binding uses the Text View compact reference notation as an **input address**, not a parser for rendered signatures. For example:
```json
{"path":"/tickets"}
{"path":"/::\"yoi.tool/Read/v1\""}
```
The first inspects an Object; the second inspects one root-scoped Interface. Object results contain `object_signature` and `interfaces: [{reference: {scope, name}, path}]`, without Interface signatures. Pass an entry's `path` directly to Inspect to obtain `{path, reference, interface_signature}`. This explicit per-entity display selection is a Yoi binding policy; it replaces the earlier automatic expansion of every Interface. Invoke continues to acquire missing observations automatically and accepts structured references, never a compact string.
Reference components follow Text View quoting: scope allows unquoted `[A-Za-z0-9_./-]+`, name allows `[A-Za-z0-9_.-]+`; other components use JSON string quoting/escapes. There is no scope inference, normalization, relative resolution, or operation suffix. A literal Object path containing `::` must be JSON-quoted inside the `path` value (for example `{"path":"\"/literal::name\""}`) to distinguish it from an Interface address. Ordinary Object paths retain Protocol path syntax, including Unicode. Invalid or unavailable Interface addresses fail rather than falling back to Object lookup.
### Model usage guidance
The three tool descriptions are the recurring model-facing usage instructions, including after compaction. Use a shallow Tree only when needed to locate entrances, inspect only relevant Objects and unknown Interface contracts, and then work through Invoke. Reuse known paths and understood contracts for the **same exact scope/name reference**; do not inspect every node or repeat Inspect as a prerequisite for every operation. Same local names under different scopes are not evidence of the same contract. Reinspect only when a reference/contract is new, changed, or no longer available in the conversation context. Cache maintenance is the Client's responsibility, not a reason for extra model calls. Use domain read/list/search/query Operations for content and large/nonindexable collections. Current authorization checks and the prohibition on blindly retrying dispatched operations remain unchanged.
The compatibility projection mounts enabled ordinary tools at:
@@ -48,9 +63,11 @@ Each compatibility Object publishes an explicit root-scoped reference:
{"scope":"/", "name":"yoi.tool/<exact-tool-registration-name>/v1"}
```
Its single operation is `call`. For this compatibility route, `Invoke.arguments` is `{ "input": <original ordinary tool argument object> }`, matching the descriptor's named Json parameter. Native projections instead receive a JSON object keyed by the descriptor's declared parameter names. Native input is decoded with the published `wip-http` descriptor-bound codec, so named and composite types are resolved, an integral JSON number remains a WIP `Number` when declared as such, and WIP `Bytes` use the codec's canonical RFC 4648 base64 JSON representation. Tool argument IDs remain JSON values; the adapter never infers a domain object or Worldspace route from them.
Its single operation is `call`. For this compatibility route, `Invoke.arguments` is `{ "input": <original ordinary tool argument object> }`, matching the descriptor's named `input` parameter. Native projections instead receive a JSON object keyed by the descriptor's declared parameter names. Native input is decoded with the published `wip-http` descriptor-bound codec, so named and composite types are resolved, an integral JSON number remains a WIP `Number` when declared as such, and WIP `Bytes` use the codec's canonical RFC 4648 base64 JSON representation. Tool argument IDs remain JSON values; the adapter never infers a domain object or Worldspace route from them.
The interface descriptor uses WIP `Json` for compatibility input and includes the exact original JSON Schema in descriptor documentation. Before execution, the Host validates the JSON value with that original schema and then delegates to the original async `Tool`. Constraints are therefore neither approximated nor silently dropped. A schema that cannot be compiled prevents WIP startup instead of creating a weaker projection.
Compatibility input is projected conservatively into JSON-shape-preserving WIP types: primitives, closed records with required/optional fields, homogeneous lists, and string enums. Local JSON Pointer references are expanded within bounded depth/node budgets; cycles and unsupported constructs stay `Json`. Open records, nullable/mixed unions, composition, and tuple elements are not falsely modeled as closed records or tagged WIP unions. The original input JSON Schema, including constraints, descriptions, defaults, and local definitions, is included in the **visible parameter summary** as well as retained documentation details. Thus a single Interface Inspect reveals the usable input contract even where WIP's type system cannot express it or an expansion budget is reached; it is never just an opaque `input: json` with hidden instructions. Full Inspect output still obeys response limits and is not silently truncated.
The call envelope remains `{ "input": <original JSON value> }`; no tagged union wrapper, field renaming, or default insertion is introduced. Before execution, the Host validates the reconstructed JSON value with the exact original schema and then delegates to the original async `Tool`. Structural projection never replaces original-schema constraints or permission checks. A schema that cannot be compiled prevents WIP startup instead of creating a weaker projection.
## Native projection extension and collisions
+21 -3
View File
@@ -44,6 +44,11 @@ removal commits registry deletion only after Runtime confirms physical deletion
or authoritative not-found. An unknown result leaves the registry in place so
retry can reconcile the provider's current state.
A retained partial-removal Workdir is listed as `cleanup_pending` with cleanliness
`unknown`. List/detail observation checks its saved identity but does not read or
hash surviving checkout content. The saved removal witness is not a current
cleanliness assertion; only an actual removal retry runs the full content checks.
## Runtime safety boundary
The Runtime keeps removal content/identity evidence outside the tree being
@@ -55,9 +60,22 @@ ignored/untracked content. Do not edit this witness manually.
Mount-safe removal currently requires Linux `openat2` and `/proc` inspection.
Unavailable inspection fails closed with `mount_check_unavailable`; there is no
fallback to recursive deletion across an unchecked filesystem boundary.
Removal retains the Runtime occupancy mutex through its filesystem effect.
Unrelated Runtime state operations can therefore wait during hashing/unlink;
releasing it would require equivalent exclusion on all attachment paths.
Runtime HTTP list, detail and removal requests run synchronous provider work on
blocking workers rather than the HTTP executor. Removal reserves only the target
Workdir under the Runtime state mutex, then releases that mutex before content
inspection and unlink. Unrelated Worker list/detail, session observation and
subscription snapshots remain available while removal runs. Conflicting use,
attachment, creation or removal of the same Workdir is rejected promptly rather
than waiting under the global mutex.
Provider leases protect in-flight creation/access and live session resources,
including their command tasks. Cloned sessions retain protection until safe close
or final resource release; passive bindings alone do not prevent removal. Removed
bindings cannot activate against a recreated Workdir with the same ID. Creation
owns a fresh root exclusively so failed creation cannot roll back another
creator's checkout or adopt an existing partial-removal directory. Reservations
are transient and released on provider success, error or unwind; they do not
replace the durable cleanup witness or attachment authority.
## Diagnostics
@@ -0,0 +1,7 @@
# Parallel Workdir reads return transient provider-busy errors
During the Workdir cleanup fix, batches of independent `Read` calls against this checkout repeatedly returned `Workdir session is unavailable: filesystem provider busy` for several calls, while one read in the same batch succeeded. Serial retries against the same paths succeeded. No live Runtime or storage repair was attempted.
This obstructed source inspection and made parallel tool batches less useful. The observations do not establish whether contention is in the filesystem provider, tool broker, or session admission layer.
Suggested investigation: reproduce two concurrent read-only tool calls on one attachment, inspect the admission/lease boundary, and distinguish ordinary read concurrency from destructive-operation exclusion. If temporary rejection is intentional, document which tool combinations may overlap and give a bounded retryable diagnostic. Do not relax cleanup or scope safety to accommodate parallel reads.
@@ -0,0 +1,10 @@
# Runtime HTTP-only production feature dependencies
While validating the Workdir cleanup fix, `cargo check -p worker-runtime --no-default-features --features http-server` failed on dependencies outside the cleanup diff:
- `http_server.rs` and `http_server/runtime_management_api.rs` use retention APIs gated by `fs-store`.
- `workspace_request.rs` imports `futures::StreamExt`, and an HTTP-enabled path in `worker_backend.rs` uses `futures::executor::block_on`, but `dep:futures` is activated by `ws-server`, not `http-server`.
The HTTP-only **test** build with `fs-store,http-server` succeeds because `futures` is also a dev-dependency; it does not prove that configuration's production compile closure. Root `cargo check` and the default Runtime build cover the normal `ws-server,fs-store` configuration.
This dependency mismatch was not repaired as part of the cleanup concurrency fix. Decide the supported feature surface explicitly, then align dependency ownership and retention route gating with it. Keep a production `cargo check` for each supported non-default configuration so dev-dependencies cannot mask this boundary.