chore(ticket): incorporate integrated Drive and structured WIP contracts

# Conflicts:
#	openapi/server-api.json
#	web/workspace/src/lib/generated/companion-api.ts
#	web/workspace/src/lib/generated/repository-api.ts
#	web/workspace/src/lib/generated/runtime-api.ts
#	web/workspace/src/lib/generated/ticket-api.ts
#	web/workspace/src/lib/generated/worker-launch-api.ts
This commit is contained in:
2026-10-09 02:54:09 +09:00
62 changed files with 11501 additions and 1008 deletions
+3 -3
View File
@@ -181,9 +181,9 @@ truncation under the existing search contract.
## Typical sequence
1. Discover `/checkouts` with depth 1; inspect its Interface and call `list`.
2. Discover an entrance or known deep directory, inspect it, call `glob`/`grep`.
3. Follow a returned file `path`, discover/inspect, call line `read`.
1. Use Tree on `/checkouts` with depth 1; Inspect `/checkouts` directly and Invoke `list`.
2. Inspect an entrance or a known deep directory directly; Invoke `glob`/`grep`.
3. Follow a returned file `path`, Inspect that path and Invoke line `read`.
4. Call `edit` or `write`; Client-managed validators protect the exact observed
object while the shared tracker enforces the prior Read.
5. Rediscover after external changes; a stale rejection is not permission to skip
+4 -4
View File
@@ -165,16 +165,16 @@ Ticket/Objective/Merge Request routes retain their T-698 contracts.
## First-Workspace example
1. `Discover(path="/", depth=1)` finds `repositories`, `workdirs` and
1. `Tree(path="/", depth=1)` finds `repositories`, `workdirs` and
`workdir-attachments` when permitted.
2. Inspect the returned Repository collection Interface and call `list` with a
2. Inspect the Repository collection path and Invoke `list` with a
bounded limit. An empty registered/visible catalog explicitly returns an empty
list; do not invent a key. Follow `next_cursor` when supplied.
3. Discover the returned item `path`, inspect its Interface and call `read`.
3. Inspect the returned item `path` directly and Invoke `read`.
`default_selector: null` means no configured default, not `main`.
4. Inspect the Workdir collection and `create` using the discovered formal key,
with optional selector, display name and Runtime under the existing contract.
5. Follow created `item.path`, discover/inspect and `attach` with a chosen
5. Follow created `item.path`, Inspect directly and Invoke `attach` with a chosen
Worker-local alias. This is separate from creation.
6. Follow `attachments_path`, `list`, then discover/read the returned connection
path to confirm alias, Workdir and effective capabilities.
+23 -11
View File
@@ -24,15 +24,17 @@ worker = { mode = "wip" }
Omission resolves to `tools`, so existing manifests, profiles, persisted snapshots, and restored Workers retain the ordinary individual-tool surface. A direct Internal SubWorker selected with `profile = "inherit"` inherits the parent mode as reusable behavior. `default` and named profile selections use that profile's own mode and do not implicitly inherit WIP.
The implementation uses the crates.io `wip-client`, `wip-protocol`, and `wip-http` **0.1.0** releases. It does not use Git/path dependencies or the old `wip-https` name. Those releases require Rust 1.88; the workspace declares `rust-version = "1.88"`, and the changed crates inherit it. WIP Host/interface crates are not needed for the async compatibility adapter: the published client/protocol/HTTP state machines remain authoritative while Yoi supplies an in-process async Host transport.
The implementation uses the published **WIP 0.2.0** Client, HTTP, Protocol and official Text View packages from **crates.io**. Exact workspace version constraints and Cargo.lock registry checksums reproduce one Protocol type source; no local attachment, path override, Git snapshot or old registry 0.1.0 substitutes for the release. Canonical scope/Text View contracts were checked against wip-reference **6086f3c5ef10aa1464ce9c824750d7f667217bfd**. See [validation and resolution checks](../development/wip-integration-validation.md). CI/Nix dependency acquisition requires no upstream Git credentials. Yoi retains its async provider/transport and existing execution boundaries; upstream owns Client cache/lifecycle, codecs and signatures.
## LLM surface and route contract
A WIP Worker exposes exactly these generic LLM tools instead of exposing every enabled ordinary tool twice:
- `Discover`: observe an object path and bounded descendants, beginning at `/`.
- `Inspect`: fetch the descriptor for an opaque interface reference returned by discovery.
- `Call`: call an operation using fresh object and interface observations.
- `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.
- `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.
The compatibility projection mounts enabled ordinary tools at:
@@ -40,13 +42,13 @@ The compatibility projection mounts enabled ordinary tools at:
/tools/<exact-tool-registration-name>
```
Each object has one opaque interface reference:
Each compatibility Object publishes an explicit root-scoped reference:
```text
yoi.tool/<exact-tool-registration-name>/v1
{"scope":"/", "name":"yoi.tool/<exact-tool-registration-name>/v1"}
```
Its single operation is `call`. For this compatibility route, `Call.arguments` is the original ordinary tool argument object. 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 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.
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.
@@ -65,7 +67,7 @@ Object resolution and operations are separate contracts. One mounted `WipProject
- A native projection replaces a compatibility projection either by the original same-route semantic capability or by an explicit registry capability claim owned by a mounted native route.
- Conflicting native claims fail startup. When native is selected, the claimed compatibility tool is hidden rather than exposed through a second entry. Normal Tool mode is unaffected because it does not install the WIP registry.
`Inspect` renders the complete effective descriptor, including contributed operations, descriptor-local named declarations, and recursive record, list, enum, and union shapes with required flags and declaration documentation. The tests `host_namespace_object_resolution_and_operation_contributions_are_independent`, `operation_contributions_reject_interface_and_target_conflicts`, and `native_projection_preserves_descriptor_and_decodes_typed_arguments_end_to_end` demonstrate root allocation, unique resolution, contribution merging, collision rejection, current call-time authorization, complete descriptor inspection, and descriptor-typed invocation.
`Inspect` delegates to official `wip-text-view::render_object` and `render_interface`; it renders the complete effective descriptor, including contributed operations, descriptor-local named declarations, and recursive record, list, enum, and union shapes with required flags and declaration documentation. The tests `host_namespace_object_resolution_and_operation_contributions_are_independent`, `operation_contributions_reject_interface_and_target_conflicts`, and `native_projection_preserves_descriptor_and_decodes_typed_arguments_end_to_end` demonstrate root allocation, unique resolution, contribution merging, collision rejection, current call-time authorization, complete descriptor inspection, and descriptor-typed invocation.
The built-in native route migration is:
@@ -83,7 +85,7 @@ The built-in Repository/Workdir reference provider allocates `/repositories`, `/
2. Mount a native collection `WipProjection` at that root with capability `repository:collection`, matching Object name and one declared interface. Static Objects underneath the root use the same capability owner prefix. A mounted collection retains its own identity, interfaces, and validator even when it has static children.
3. For dynamic items, register one `WipDynamicMount` on the collection with capability `repository:item`. A foreign capability owner is rejected. Its `WipDynamicItemResolver` owns reference acceptance, Object identity, and current Object validator. It returns only a bounded direct child; it must not reinterpret a reference as another namespace or grant permission from existence.
4. The reference provider supplies its read operations and handlers independently of management Feature enablement. An Object-only provider may use an empty operation descriptor. Enabled management Features register `WipOperationContribution` for static Objects or `WipDynamicOperationContribution` for a dynamic family; they do not allocate the namespace again or replace its resolver.
5. Contributions use the existing interface reference and identical format, documentation, and type declarations, supplying only their new operations. Interface references are global: extending a descriptor that is also mounted elsewhere must not create different descriptors/validators under the same reference (registration fails). Use separate references for collection and item contracts. Failed contributions leave the registry unchanged.
5. Contributions use the existing interface reference and identical format, documentation, and type declarations, supplying only their new operations. Interface references are exact (scope, name) keys: extending a descriptor that is also mounted elsewhere must not create different descriptors/validators under the same reference (registration fails). Use separate references for collection and item contracts. Failed contributions leave the registry unchanged.
6. Handlers are responsible for checking current target capability and current subject authorization before dispatch. Registration/discovery is metadata, not a grant. A resolver/handler must retain the original permission identity and domain audit/failure contracts. Revocation after discovery must fail before provider dispatch. Compatibility mounts are restricted to `/tools/<tool-name>` and cannot bypass namespace ownership or republish legacy routes.
Tests `management_enablement_is_independent_of_read_and_operation_permissions` and `contributed_interface_invalidates_observations_and_restore_requires_discovery` cover all eight enablement/read/manage combinations, direct-call rejection, effective descriptor changes, fresh runtime isolation under the same Worker identity, reset, and post-observation revocation.
@@ -103,13 +105,13 @@ The Worldspace contains only the operations registered from enabled Features and
Filesystem scope, provider Workdir capability checks, Backend Workspace authority, Feature enablement, and input-specific restrictions stay in the original tool implementation and are checked again at invocation. `ask` permissions remain denied fail-closed because the runtime has no approval protocol. The gateway does not mint authority or expose authentication material.
Pre/post Engine history still records one bounded `Call` result, while the compatibility result retains the original `ToolOutput`, including attachments and normal Engine output pruning. WIP call audit records retain the route, operation, request identity, and terminal classification.
Pre/post Engine history still records one bounded `Invoke` result, while the compatibility result retains the original `ToolOutput`, including attachments and normal Engine output pruning. WIP call audit records retain the route, operation, request identity, and terminal classification.
## Client lifetime, restoration, and compaction
The stateful `wip-client::Client` is owned by one Worker WIP runtime. Sessions are keyed by the canonical endpoint and an opaque security-context identity derived by the Host from Workspace, Worker, and session identity. Authentication credentials are not included in that identity and are never emitted to descriptors, tool output, or history.
Known Space and interface observations are therefore not shared across Workers, endpoints, or security contexts. A restored Worker creates a new runtime/client and must explore again. `Discover(reset = true)` drops all observations before reconnect/authority-change exploration; `refresh = true` explicitly supersedes one cached observation. A normal compaction keeps the live runtime but the three gateway schemas are supplied again on every LLM request, including the instruction to begin discovery at `/`; the compacted transcript is not treated as cache authority.
Known Space and interface observations are therefore not shared across Workers, endpoints, or security contexts. A restored Worker creates a new runtime/client and must explore again. `refresh = true` explicitly supersedes requested retrievals. Old string references in saved history remain historical text, not cache/wire authority; observations are runtime-only and are not persisted or restored. Resume by inspecting the target path, not by migrating an opaque display string. A normal compaction keeps the live runtime but the three gateway schemas are supplied again on every LLM request, including direct Inspect and indexable Tree semantics; the compacted transcript is not treated as cache authority.
Saved Session/history entries remain append-only evidence and are never rewritten or replayed as calls. In particular, historical `/features/<feature>/...` text stays displayable but is not a current route alias. Passing such a legacy path to discovery or call returns `NotFound` with guidance to rediscover from `/`; the Host does not translate it, resolve it under another namespace, or expose old and new routes in parallel.
@@ -138,3 +140,13 @@ The runtime tracks bounded counters for:
- successful operations.
These values are returned with discovery/inspection output and are intended for comparing prompt input volume, exploration round trips, and representative operation success with ordinary Tool mode. No fixed reduction percentage is promised.
## Scoped publication and display boundaries
References are structured everywhere; wire requests reject legacy/display strings. Root and self scopes are valid; ancestry uses canonical path segments, not string prefixes. Contextual descriptors use the resolved Object path as their explicit self scope, not an encoded suffix on the local name. Fetching a self-scoped Interface freezes descriptor/validator and optional scope Object ref from the same live projection. A scope without a ref is valid; the adapter does not invent one. Calls check target existence, Object preconditions, scope/membership/ref, then Interface preconditions and arguments, with the selected descriptor and handler pinned for execution/result validation. Existing providers repeat current authorization and their captured Workdir/Workspace metadata checks at their execution/commit boundary. The registered artifacts alone are not call authority.
Separate Interface namespaces on one static Object can be registered with `mount_interface`; the owner/identity cannot be replaced and duplicate Interface keys fail. Inspect preserves each Interface reference, even with identical operation names, and Invoke selects the exact namespace. Contribution merging retains one Interface and disjoint operation names.
Official signature quoting, escapes and summary layout are preserved verbatim. Host documentation is untrusted data in Tool output, not instructions. RenderError categories and the failed path/reference are reported as display failures. Library input limits and Yoi envelope limits reject the entire display rather than truncating it or reporting no operations. No signature parser, shorthand-input parser, independent lexer, or custom escape engine is installed.
Typed Entry results remain values; no eager result acquisition, guessed string-path conversion, or inferred indexable edges occur. A later Inspect failure never reclassifies a completed successful operation. FS indexable/list policy is a separate provider concern (T-714), not Client-side search/ranking.
+106 -2
View File
@@ -5,8 +5,9 @@
Drive is a Workspace-owned **latest-version document tree**, not a mounted or
POSIX-compatible filesystem. `workspace-drive` owns storage, hierarchy, revision
conflicts, mutation receipts, bounded reads/search, and garbage collection.
`WorkspaceApi::drive` is the trusted Server adapter. Authorization and HTTP DTOs
belong to T-722; Worker/Web clients and end-to-end routing belong to T-723–725.
`WorkspaceApi::drive` is the trusted Server adapter. The authorized HTTP API and
Backend-managed grants are documented below. Worker Tools/WIP, Web UI, and full
end-to-end routing belong to T-723–725.
Session attachments remain Session-owned and are not Drive authority. Worker,
Session, and Workdir cleanup do not delete Drive.
@@ -262,3 +263,106 @@ The hermetic backup test stops writers, snapshots actual FeatureStorage SQLite,
copies actual LocalFileSystem blobs, restores into absent roots, and checks stable
IDs/latest content/receipts and non-reused ID allocation. It does not validate a
production backup scheduler, volume snapshot, or physical power cut.
## Authorized typed HTTP API
The Rust `server-api` contract owns `/api/w/{workspace_id}/drive/` operations:
- `GET root`, `metadata`, `list`, `search`, `read-text`, `read-chunk`, `download`;
- `POST mutate` (create folder/bounded UTF-8 text, replace text, relocate, delete);
- `PUT upload` (binary body with flat query metadata);
- `GET requests/{request_id}` for the committed receipt snapshot;
- owner-controlled `POST/GET grants` and `DELETE grants/{grant_id}`.
Ordinary usage follows the existing member-facing authenticated Server-user
policy. Non-ownership alone does not deny use. Grant management follows the
existing Workspace-owner account boundary. No new general membership ACL is
introduced. Browser/API-token identity is supplied by authentication middleware;
user/account existence and active Workspace state are checked again in the
operation transaction. Cookie mutations require the configured application
Origin through the existing middleware. No ordinary DTO accepts an actor.
Runtime-forwarded requests require the existing signed source proof and live
Runtime/Worker catalog membership. Workers receive an explicit whole-Drive
`read_only` or `read_write` grant, independently of Profile, Subject, Ticket,
Workdir or commands. Incomplete/mismatched Runtime or Worker identity cannot fall
back to a browser actor. Grant creation rechecks owner, active Workspace, and
existing live Worker in the Server DB transaction; active access changes require
revoking the previous grant first (no silent downgrade). Migration 84 stores
creation/revocation actor and time. Removal fences and catalog deletion revoke
access and retain audit; grant rows cascade with Workspace deletion. No alternate
Worker registry or Drive Workdir attachment is created.
A clone-bound Drive authorizer queries the attached Server authority under every
client-operation `BEGIN IMMEDIATE`, including receipt replay/result queries.
The lock spans validation, blob persistence and DB publication. Grant revocation
and Worker removal use the same Server DB write authority: whichever transaction
wins first is ordered first. A mutation committing before revocation is valid;
a revoked cached handle cannot commit later. Upload admission also checks access
before consuming the body, but that admission is not a lease: publication always
rechecks current access. Download checks authorization separately for every
chunk, and stops on revocation, deletion, revision expiry or storage failure.
References contain **both** Workspace ID and stable decimal node ID. JSON uses
`DriveEntryRef`; flat GET/binary queries require `entry_workspace_id` matching the
route Workspace before resolving `id`/`parent_id`. IDs/revisions are canonical
positive decimal strings within signed 64-bit range; file sizes/offsets are
bounded `u32`. List/search cursors carry Workspace identity and the last node ID;
they are continuation hints, not capabilities or snapshots. Returned `latest_url`
is a relative authenticated URL bound to Workspace and ID, independent of logical
name/parent. It confers neither public sharing nor approval. File URLs download;
folder URLs return metadata. Deletion/recreation never reuses the old reference.
Web upload consumes binary HTTP frames with an observed **16 MiB** ceiling and
checks declared size and lowercase SHA-256 before publication. Oversized announced
or received data, mismatches, aborted bodies and I/O errors never return success.
The storage boundary currently requires a whole-file Vec, so uploads retain at
most one bounded binary file in memory before calling T-721; they are not
constant-memory object-store multipart uploads and are never expanded to
JSON/base64. Runtime source-proof verification separately buffers a bounded body
before granting trusted ingress, as in other signed Server operations. Web
downloads stream **64 KiB** revision-fixed chunks; they do not materialize the
whole file. Generated Rust clients retain their explicit bounded-response policy
and return exact `BinaryBody` bytes. Worker JSON-facing adapters can request
bounded text or binary chunks through this same contract, but Tools/WIP and
model-context/image presentation belong to T-723; this API does not emit large
base64 JSON blobs.
Downloads validate bare MIME types and always use `Content-Disposition:
attachment` with percent-encoded UTF-8 names, `nosniff`, a sandbox/default-none
CSP, `private, no-store`, and a Workspace/node/revision ETag. Arbitrary HTML/SVG
bytes are storable, not safe app-origin inline previews. Content length is exact;
if a later chunk loses authority or expires, the response stream fails rather
than returning another generation or a successful truncated file. Even an empty
file validates its referenced blob before HTTP success. Conditional 304/range
HTTP semantics are not added; revision-selected chunk reads are explicit.
Errors use fixed, path-free typed codes: `denied`, `not_found`, `conflict`,
`invalid`, `limit`, `storage_unavailable`, `outcome_unknown`. SQL/commit/task
uncertainty at a mutation boundary is `outcome_unknown`/`unknown`; known rejection
or blob persistence failure is `not_committed`. A successful DB commit alone
returns a mutation response. After a lost response, query the same request ID;
`uncommitted` only means no committed receipt in that snapshot and must not be
interpreted as proof that an in-flight request can never commit. Exact replay uses
the same identity/payload/transport-bound actor and current permissions. Never
blindly create a fresh request ID to resolve an unknown outcome. Physical paths,
blob keys and raw provider errors are not public.
Contract regeneration/freshness:
```sh
cargo run -q -p server-api --example export_openapi -- openapi/server-api.json
cargo run -q -p server-api --example export_openapi -- --check openapi/server-api.json
cargo run -q -p server-api --features typescript --example generate_drive_api_types > web/workspace/src/lib/generated/drive-api.ts
deno fmt web/workspace/src/lib/generated/drive-api.ts
cargo test -p server-api --features typescript generated_drive_api_contract_is_current
# Existing OpenAPI-derived projections embed the whole-contract digest:
for example in generate_repository_openapi_types generate_runtime_api_types generate_ticket_api_types generate_companion_api_types generate_worker_launch_api_types; do
cargo run -q -p server-api --example "$example"
cargo run -q -p server-api --example "$example" -- --check
done
```
The existing BinaryBody contract also supports binary **success responses**,
including declared response headers, without changing binary request bytes or
JSON/error behavior. It exports inline OpenAPI binary bodies, not JSON byte arrays.
@@ -0,0 +1,124 @@
# Scoped WIP integration validation
## Released dependency and resolution
The adopted Client, HTTP, Protocol and official Text View are **crates.io 0.2.0**,
with exact `=0.2.0` workspace declarations and registry checksums in Cargo.lock.
`cargo info <package>@0.2.0` confirmed all four published packages (Rust 1.88).
`node scripts/verify-wip-dependencies.mjs` checks actual locked/offline Cargo
resolution: all WIP packages use registry 0.2.0, each required package occurs
once, and Protocol has one source. No path/Git override or attached checkout is
used. The earlier unreleased 0.1.0 source snapshot and vendor verifier were
removed when T-713 thread sequence 26 specified 0.2.0.
Canonical contract reference: wip-reference
`6086f3c5ef10aa1464ce9c824750d7f667217bfd`. This reference documents the contract;
Cargo resolves the release, not that checkout or an unreleased Rust revision.
## Executed checks on registry 0.2.0
- `cargo test -p worker --locked --offline`: **894 unit + 110 integration tests
passed**, no ignored/failed tests. This includes ordinary Tools mode, Feature
permission/revocation, restore, session/history and controller integration.
- Narrow development checks: `wip::binding` (25), `wip::provider_tests` (12), existing
`wip::tests` and workdir projection tests (43), checkout transports/providers
(20), workspace-config production/authority tests (19). These are included
in the complete worker run.
- Published SDK tests via `cargo test -p wip-client -p wip-http -p wip-protocol
-p wip-text-view --locked --offline`: Text View **16 public signature/token/golden
tests + 4 doctests**; Client **63 adapter/runtime tests**; HTTP **38 tests + 1
doctest**; Protocol **22 tests + 1 doctest**. Tests run from the registry packages,
not substituted source or removed vendor directories.
- Root `cargo check --locked --offline` passed, including normal TUI, CLI,
Runtime and Workspace Server compile closure.
- `cargo fmt --all -- --check` and `git diff --check HEAD` passed.
- `nix build --no-link .#yoi.cargoDeps` passed with the updated registry dependency
hash. This validates credential-free dependency acquisition, not a full Nix
binary/image build or deployment update.
## Current target compatibility (preview, not integration)
Source runtime at `23cf6c4f882ce78985ba4bd673751cebe64e2d87` and current develop
`b5ea162f838fc36e364edec9ab6689292b59cffd` produce the conflict-free `git merge-tree`
preview tree `7ef3545b635cbdfc5e24658f6d1532e0f8b0947c`. An archive of this tree,
without a branch/ref change, passed root locked/offline Cargo check, all **91**
Server API TypeScript tests (including OpenAPI/checked-in generator freshness),
registry WIP resolution checks, and Nix dependency acquisition with the same hash.
T-722's API macros, Server API/Drive/Server source, OpenAPI and generated TS blobs
are unchanged from develop in the combined tree; no artifact overwrite or
regeneration is necessary for this source change. The later added same-name scope
regression changes tests only, not the validated runtime or shared contracts.
The initial archive check reused a Cargo target directory; returning to the older
main checkout exposed stale preview Server API artifacts. All local workspace
artifacts were invalidated, and a fresh main root check and complete **894 + 110**
Worker suite passed. Use an isolated target directory for future cross-tree checks.
No target push, integration branch, deployment, or live dogfood update was made.
Orchestrator readiness/integration must still resolve the then-current target.
## Contract evidence
`crates/worker/src/wip/binding.rs` tests exercise fresh/loading/stale/failed and
capacity-blocked acquisition, explicit refresh, superseded responses, retrieval
ownership cleanup, output limits, direct unseen-path Inspect, official unmodified
signature/path envelopes, structured Interface input and complete edge-only trees.
They invoke the registered three-tool surface for a search returning typed Entry
paths, inspect only a selected nonindexable path, dispatch the selected operation,
and verify that a later Inspect failure neither fails nor replays an earlier
successful operation. Interface acquisition failures are not empty operation lists.
`provider_tests.rs` exercises the actual Yoi adapter for root/self scope, optional
refs, copied scope_ref, different scopes with identical names/operations, shape vs
membership errors, validator/ref absence/mismatch and protocol failure precedence.
It replaces a dynamic scope Object identity, observes both stale sides after
InterfaceMismatch, reacquires without replay, and confirms direct NotFound ends
safe Interface reuse. An in-flight operation survives descriptor refresh using
its exact frozen Host and Client descriptors rather than the newer return type.
`ancestor_tests.rs` covers the independent review finding P1_CURRENT_ANCESTOR_SCOPE:
valid live ancestor refs that differ from registration placeholders, root `/` and
intermediate provider-owned ancestors, ref-less and ref-bearing scope deletion
without a prior scope Inspect, rejected cached dispatch and orphan observation,
replacement/republication without restoring old Interface registrations,
same-name scope replacement or loss of public ref rejecting copied old metadata
without replay (and later explicit Inspect/Invoke copying only the new optional ref),
shape/target/Object-validator/Interface-mismatch precedence, and frozen in-flight
ancestor Descriptor/handler/result validation after replacement. Valid Invoke
makes one provider publication call for the target, not a separate scope lookup.
Existing checkout tests retain commit-time captured Workdir/connection/validator
checks, alias reuse/restore fencing, inode replacement rejection, authorization,
shared prior-read tracking, exact post-operation validators, cooperative
cancellation and unknown/lost/malformed responses without retries. Existing native
Ticket/Objective/Merge Request tests retain scoped Workspace authority and Feature
permission separation; compatibility Invoke retains original schema validation,
permission identity and ToolOutput/attachments.
## Downstream provider seams
- Public projection/contribution Interface fields use
`wip_protocol::InterfaceReference { scope, name }` from registry 0.2.0.
- `WipSubtreeProvider::publication` returns a `WipPublication` that captures target,
current scope Object, Descriptor/validator and handler at one provider boundary.
Mutable ancestors must not be resolved independently after selecting a target.
`scope: None` ends usable publication, even without a public ref; it is not a
ref-less published Object. Host checks and observation never substitute the
root registration placeholder, and Interface fetch never falls back to retained
provider registrations. Old registrations must end when their scope lifetime
ends. Published ancestor scopes outside the subtree remain Host-owned.
- Contextual/self-scope publishers use `WipPublication::self_scoped` on their exact
provider snapshot; references are explicit paths, not an encoded `/@/` suffix.
Checkout and Workspace Config retain their captured provider/Backend execution
and commit fences. Ref-less publication remains legitimate.
- `WipRuntime::{tree, inspect, invoke}` is the object-centered integration seam.
Inspect uses official summary-only signatures and typed rendering failures.
- `WipMountRegistry::mount_interface` adds a separate static Interface namespace
without replacing Object ownership or flattening same-named operations. It does
not overlay stale registration metadata onto a live subtree provider.
- FS indexable boundaries and directory.list remain provider policy. This change
deliberately does not implement the separate T-714 boundary/list migration.
Relevant transport/commit tests are `checkout_wip_tests.rs`,
`checkout_http_tests.rs`, and `checkout_race_tests.rs`.
- Worldspace state is runtime-only. Historical opaque references in append-only
session/tool history are not migrated into cache or parsed for a guessed scope;
a restored Client starts with fresh observations and direct path Inspect.
+18
View File
@@ -0,0 +1,18 @@
# T-722: SubWorker cwd and logical path friction
During delegation from the assigned repository Workdir, a child started with
`cwd: crates/server-api` and readable policy paths under repository-root
`docs/development`. Its Read calls using repository-relative logical paths could
not read the required testing strategy; absolute paths were rejected as invalid
logical paths too. The child correctly stopped without edits. The parent
inspected the committed child session, stopped that idle child, and recreated it
with repository-root cwd and explicit read-only repository scope plus write scope
limited to server-api. Policy reads and implementation then succeeded.
The current observable behavior appears to root child filesystem tools at the
selected cwd, rather than making cwd only the command default as the spawn-tool
description states. This makes repository-root logical paths surprising. Consider
keeping the attachment root invariant and applying cwd only to command execution,
or documenting/returning a distinct filesystem base explicitly. Do not encourage
absolute paths, parent traversal, or broader write grants as a workaround. This
report records a tool usability issue, not additional Ticket requirements.