fix: integrate develop and preserve invocation notification recovery
This commit is contained in:
+3
-1
@@ -35,7 +35,9 @@ It is not a dumping ground for external research, old plans, API inventories, or
|
||||
27. [`development/subjektiv-product-cutover.md`](development/subjektiv-product-cutover.md) — legacy Workspace Memoryからsubjektivへのoperator cutover、explicit reset、backup/rollback runbook。
|
||||
28. [`design/worker-wip-mode.md`](design/worker-wip-mode.md) — explicit-opt-in Worker WIP mode, Worldspace projection, authority, cache, and retry contracts.
|
||||
29. [`design/objective-wip-projection.md`](design/objective-wip-projection.md) — Host-assigned Objective collection/item routes, operation mapping, Backend authority, bounds, and compatibility suppression.
|
||||
30. [`design/feature-chat-invocations.md`](design/feature-chat-invocations.md) — declarative `/` invocation identity, grammar, completion, typed draft, attachment staging, execution, and authority boundaries.
|
||||
30. [`design/ticket-wip-projection.md`](design/ticket-wip-projection.md) — Host-assigned Ticket collection/item routes, role-specific operations, route identity, and typed Backend preservation.
|
||||
31. [`design/merge-request-wip-projection.md`](design/merge-request-wip-projection.md) — Host-assigned Merge Request routes and preserved review/integration authority gates.
|
||||
32. [`design/feature-chat-invocations.md`](design/feature-chat-invocations.md) — declarative `/` invocation identity, grammar, completion, typed draft, attachment staging, execution, and authority boundaries.
|
||||
|
||||
## What belongs here
|
||||
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
When a Worker explicitly runs in `wip` mode and its Merge Request Feature has at least one enabled operation, the Worker Host projects that exact operation set as native Worldspace objects. The projection is an adapter over the existing scoped Workspace Merge Request tools and Backend routes. It does not create a second Merge Request store, provider integration path, review grant, approval rule, or completion authority.
|
||||
|
||||
The Host allocates `/features/merge-request` and the Feature mounts:
|
||||
The Host assigns the Merge Request provider the root `merge-requests` namespace through `WipMountRegistry` and mounts:
|
||||
|
||||
```text
|
||||
/features/merge-request/merge-requests
|
||||
/features/merge-request/merge-requests/<merge-request-id>
|
||||
/merge-requests
|
||||
/merge-requests/<merge-request-id>
|
||||
```
|
||||
|
||||
There is no Feature Object or `/features/merge-request` compatibility alias. Legacy paths remain historical display data only and fail as current input with rediscovery guidance.
|
||||
|
||||
An item identity is a single canonical path segment. Nested paths and percent-encoded target substitution do not resolve. Item operations remove `merge_request_id` from their descriptor and reconstruct it only from the selected object route. Discovery does not mint authority: every call still uses the Worker's scoped `WorkspaceClient`, the enabled Feature flags, ordinary Tool permission rules, and the Backend's Workspace, repository, assignment, provider-ref, review, and integration checks.
|
||||
|
||||
## Current Feature inventory
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
When a Worker explicitly runs in `wip` mode and the Objective Feature is enabled, the Worker Host projects Objectives as native Worldspace objects. The projection is an adapter over the existing scoped Workspace API. It does not introduce another Objective store, state machine, reference resolver, or audit path.
|
||||
|
||||
The Host allocates `/features/objective` to the Feature through `WipMountRegistry`. The Objective Feature then mounts:
|
||||
The Host assigns the Objective provider the root `objectives` namespace through `WipMountRegistry` and mounts:
|
||||
|
||||
```text
|
||||
/features/objective/objectives
|
||||
/features/objective/objectives/<objective-reference>
|
||||
/objectives
|
||||
/objectives/<objective-reference>
|
||||
```
|
||||
|
||||
There is no Feature Object or `/features/objective` compatibility alias. Legacy paths are retained only as historical text and fail as current inputs with rediscovery guidance.
|
||||
|
||||
`<objective-reference>` is either a canonical `O-<digits>` key or an existing canonical internal alphanumeric ID. Only one direct child segment is accepted. Nested suffixes, Ticket keys, and unrelated or hidden prefixes do not resolve as Objective objects.
|
||||
|
||||
The Backend remains authoritative for existence, `O-*`/internal-ID resolution, Workspace scope, validation, audit events, revision generation, pagination, body/event bounds, and linked-Ticket validation. A discovered route is not independent authority; every operation still uses the Worker's current `WorkspaceClient`.
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
When a Worker explicitly runs in `wip` mode and its Ticket Feature is enabled, the Worker Host projects the enabled Ticket surface as native Worldspace objects. The projection is an adapter over the existing scoped Workspace Ticket API and typed Ticket tools. It does not add a Ticket store, resolver, audit path, state machine, readiness rule, queue path, or relation implementation.
|
||||
|
||||
The Host allocates `/features/ticket` and the Feature mounts:
|
||||
The Host assigns the Ticket provider the root `tickets` namespace through `WipMountRegistry` and mounts:
|
||||
|
||||
```text
|
||||
/features/ticket/tickets
|
||||
/features/ticket/tickets/<ticket-reference>
|
||||
/tickets
|
||||
/tickets/<ticket-reference>
|
||||
```
|
||||
|
||||
There is no Feature Object or `/features/ticket` compatibility alias. A legacy path supplied as current input fails with rediscovery guidance; saved history containing that text is left unchanged.
|
||||
|
||||
`<ticket-reference>` is either a canonical `T-<digits>` key or an existing canonical internal alphanumeric ID. Only a direct child is accepted. Nested suffixes, Objective keys, unrelated prefixes, and hidden routes do not resolve.
|
||||
|
||||
Every call retains the Worker's scoped `WorkspaceClient`, current Ticket Feature access, and ordinary Tool permission policy. Discovery is not mutation authority. A direct call to an unpublished operation fails even when the caller knows its name. `deny` and interactive `ask` permission outcomes fail closed before Backend dispatch.
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
# Repository, Workdir and attachment WIP projection
|
||||
|
||||
## Objects and operations
|
||||
|
||||
The Host owns these root namespaces, using the same `WipMountRegistry`
|
||||
namespace/resolver/contribution contracts as Tickets, Objectives and Merge Requests:
|
||||
|
||||
```text
|
||||
/
|
||||
├── repositories list
|
||||
│ └── <encoded repository key> read
|
||||
├── workdirs list, create
|
||||
│ └── <encoded Workdir ID> read, attach, delete (when supported)
|
||||
└── workdir-attachments list
|
||||
└── <connection lifetime ID> read, detach
|
||||
```
|
||||
|
||||
Operations are Interface declarations, **not child files**. There is no
|
||||
`/features/manage-workdir`, no writable Repository catalog and no Repository
|
||||
content tree here. `/checkouts` content projection is a separate provider (T-699),
|
||||
as is Workspace configuration (T-695). Management Objects do not grant access to
|
||||
unattached contents. A future content provider should return its entrance from
|
||||
an authorized, live attachment; it must not infer content/command capability
|
||||
from catalog or lifecycle access.
|
||||
|
||||
`path` in inventory results is an absolute WIP Object path. It is a reference,
|
||||
not an OS path, a capability grant, or an instruction to reinterpret another
|
||||
string argument as a route. Source Repository references use `repository_path`;
|
||||
attachment references use `workdir_path`. Attach results include
|
||||
`attachments_path` to discover the current connection and its lifetime ID.
|
||||
|
||||
### Identity and route encoding
|
||||
|
||||
Repository identity is the formal Backend `repository_key`, never its display
|
||||
name or a guessed `main`. Workdir identity is `working_directory_id`, never a
|
||||
Worker-local alias. A segment containing only ASCII letters, digits, `-`, `_`
|
||||
is unchanged. All other UTF-8 identities are encoded as `~` followed by lowercase
|
||||
hexadecimal UTF-8 bytes. The `~` marker is itself always encoded. Only the
|
||||
canonical encoding is accepted; no alternate spellings, recursive URL decoding,
|
||||
case folding, slash traversal or namespace fallback are accepted. For example,
|
||||
`repo/name` is `/repositories/~7265706f2f6e616d65`. This is injective and accepts
|
||||
existing valid keys, including Unicode and slash-containing identities.
|
||||
|
||||
Attachment identity is a fresh opaque Backend connection ID for each lifetime,
|
||||
including detach/reattach to the **same** alias and Workdir. Read exposes alias,
|
||||
Workdir ID and effective attachment capabilities as attributes. Workdir existence
|
||||
and Worker connection are separate Objects. Detaching a connection does not
|
||||
remove the Workdir or delete a logical settings space.
|
||||
|
||||
## Feature and authority separation
|
||||
|
||||
`feature.workdir_catalog.enabled` independently supplies read-only Repository,
|
||||
Workdir and attachment reference operations. It defaults enabled so a WIP Worker
|
||||
with Workspace authority and appropriate permissions can find registered keys
|
||||
without Ticket or conversation hints. It does not add ordinary Tools or require
|
||||
a filesystem/Bash location. Standalone Workers without Workspace authority have
|
||||
no Workspace catalog mounted.
|
||||
|
||||
`feature.manage_workdir.enabled` supplies management operation implementations
|
||||
on the **same Objects** using `contribute_operations` and
|
||||
`contribute_dynamic_operations`. It remains default disabled. It neither owns
|
||||
another resolver nor confers permission. The object provider is unique; duplicate
|
||||
namespace, route, operation name or inconsistent Interface contributions fail at
|
||||
registration through the common registry.
|
||||
|
||||
Native permission identities are:
|
||||
|
||||
| Operation | Manifest permission identity | Bound identity in permission input |
|
||||
| --- | --- | --- |
|
||||
| repositories.list | RepositoryList | list arguments |
|
||||
| repository.read | RepositoryRead | repository_key |
|
||||
| workdirs.list | WorkdirList | list arguments |
|
||||
| workdir.read | WorkdirRead | working_directory_id |
|
||||
| workdirs.create | WorkdirCreate | original create arguments |
|
||||
| workdir.attach | WorkdirAttach | working_directory_id + alias |
|
||||
| workdir.delete | WorkdirDelete | working_directory_id + reason |
|
||||
| attachments.list | WorkdirAttachmentList | list arguments |
|
||||
| attachment.read | WorkdirAttachmentRead | connection_id |
|
||||
| attachment.detach | WorkdirDetach | current bound alias |
|
||||
|
||||
Read permissions gate direct item resolution as well as list item visibility.
|
||||
The manifest's existing default policy is retained; `ask` is denied fail-closed.
|
||||
An argument-dependent policy may advertise an operation that could be allowed,
|
||||
but every call checks its exact reconstructed input before execution. Mutation
|
||||
arguments cannot override path-bound Workdir or connection identity. Having
|
||||
RepositoryRead is not WorkdirCreate; inventory/management permissions are not
|
||||
file access, delegation or command execution grants. Backend caller/Workspace
|
||||
identity, source proof, attachment capability ceilings and lifecycle policy are
|
||||
checked by the existing paths on every request.
|
||||
|
||||
## Contextual Interfaces and stale observations
|
||||
|
||||
Providers opt into common Host contextual Interfaces. Operation publication is
|
||||
the intersection of registered implementation, current target support and current
|
||||
subject policy. The collection reference feature can remain available while the
|
||||
management feature is disabled. External Workdirs without cleanup authority do
|
||||
not expose delete. Only currently supported lifecycle operations are advertised;
|
||||
no delete/command is added to logical attachments solely because they appear as
|
||||
workspaces.
|
||||
|
||||
A contextual Interface reference is opaque and path-qualified as
|
||||
`<base>/@/<hex UTF-8 Object path>`. Clients must use the returned reference, not
|
||||
construct it. Fetch and call freshly resolve the same Object and filtered
|
||||
Interface; base references cannot fetch an unfiltered descriptor. Descriptor and
|
||||
Object validators invalidate old observations after target/connection/permission
|
||||
changes. Validators are managed by the WIP Client, not manually by the LLM.
|
||||
Cached Interface possession and known direct paths never bypass current checks.
|
||||
Historic session text remains append-only and is not rewritten or replayed.
|
||||
|
||||
## Backend lifecycle and safe output
|
||||
|
||||
Catalogs are request-time projections of existing Backend authority, not another
|
||||
store or synchronization job. WIP list pages default to 50 and accept 1–100
|
||||
items. Repository pages sort the existing complete Repository catalog by stable
|
||||
key. Workdir pages use the signed caller-bound Backend
|
||||
`workers/self/workdir-catalog` operation, with SQL keyset paging over the existing
|
||||
Workdir registry in stable ID order. This is not the legacy bounded
|
||||
`working-directories` browser/Tool snapshot: Workdirs older than its 200-record
|
||||
cap remain reachable. `next_cursor` advances over scanned rows even when the
|
||||
current read policy or unsupported legacy source makes a page sparse or empty;
|
||||
`empty` describes that page, and `has_more` remains authoritative for progress.
|
||||
Attachment pages use the Backend's SQL-bounded, alias-ordered limit/offset query
|
||||
and opaque `offset:<n>` cursors. Both Workdir and attachment responses supply an
|
||||
opaque complete-set `revision` derived from existing authoritative records in
|
||||
the same database snapshot as the page, not by hashing the first page. The Host
|
||||
uses this complete-set revision for the collection Object validator. A lifetime
|
||||
or capability change beyond row 50 therefore invalidates old collection
|
||||
observations without adding a ledger or revision store. A cursor is not
|
||||
a snapshot or authority grant: restart listing after concurrent collection
|
||||
changes. Filtering by exact `connection_id` is applied in the caller-scoped
|
||||
Backend ledger before paging, so direct item lookup also works beyond the first
|
||||
page. Unknown/expired IDs yield no item, never a current alias substitute.
|
||||
Repository projection uses an explicit field
|
||||
allowlist: formal key, kind/provider, any existing display metadata and explicit
|
||||
nullable default selector. Source URI/path, credentials, remotes, Runtime
|
||||
connection information and internal fingerprints are not model-visible.
|
||||
Workdir projection includes stable ID, optional display name, public source kind
|
||||
and Repository key, existing selector/ref/tree, status, cleanliness and occupancy
|
||||
when available. Cleanup handles and External grant internals are not forwarded.
|
||||
No missing attributes or implicit selectors are fabricated. Backend errors are
|
||||
sanitized rather than forwarding raw diagnostic bodies with possible host paths.
|
||||
|
||||
Create and attach reuse the ordinary Workdir backend, request identity,
|
||||
Worker-session router, mutation lock and Internal SubWorker lifecycle hooks.
|
||||
Creation does **not** attach. Attach installs the Backend-attenuated session
|
||||
capabilities, never a fabricated `ALL` capability for External Workdirs. Detach
|
||||
uses the same begin/finish/cancel-detach path and command/operation exclusion as
|
||||
Tools; the Backend checks expected connection identity under its existing
|
||||
current-Worker lifecycle lock before closing sessions, then conditionally
|
||||
updates that exact row in the existing connection ledger. Alias reuse cannot
|
||||
retarget an old connection operation. Compensation retains the original
|
||||
connection identity. Existing removal dispositions `removed`, `retained`, and
|
||||
`attention_required`, plus retryability, remain intact.
|
||||
|
||||
Stale identity/validator rejection is distinct from unknown operation outcome.
|
||||
Transport failure, invalid post-dispatch response or uncertain lifecycle failure
|
||||
is **not** proof that no effect occurred; it must not be automatically retried.
|
||||
Inspect current state or request operator guidance. No new retry or attachment
|
||||
ledger is introduced by WIP.
|
||||
|
||||
When native management is mounted, `WorkdirList/Create/Attach/Detach/Delete` are
|
||||
claimed as represented native capabilities, so `/tools/Workdir*` is not also
|
||||
published. Ordinary Tools mode keeps its names and inputs. Existing native
|
||||
Ticket/Objective/Merge Request routes retain their T-698 contracts.
|
||||
|
||||
## First-Workspace example
|
||||
|
||||
1. `WipDiscover(path="/", depth=1)` finds `repositories`, `workdirs` and
|
||||
`workdir-attachments` when permitted.
|
||||
2. Inspect the returned Repository collection Interface and call `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`.
|
||||
`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
|
||||
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.
|
||||
7. Call that connection's `detach` with no identity override. The observed
|
||||
lifetime ID guards alias reuse; the Workdir remains in its inventory.
|
||||
|
||||
Each step uses current WIP observations and no Ticket-derived key, host path,
|
||||
Runtime endpoint or manual validator. Explicitly refresh/reset discovery after
|
||||
external changes and before reconstructing a rejected stale call.
|
||||
@@ -52,21 +52,47 @@ The interface descriptor uses WIP `Json` for compatibility input and includes th
|
||||
|
||||
## Native projection extension and collisions
|
||||
|
||||
`worker::wip::WipMountRegistry` is the Host-owned mount allocator. A Feature can independently construct a `WipProjection` with an async `WipOperationHandler`, then pass its aggregate registry through `install_wip_mode_with_mounts` before compatibility finalization. A Feature first requests a Host-owned `/features/<feature>` namespace with `allocate_feature_route`; checked direct-child joins prevent a Feature from claiming an ambient global route.
|
||||
`worker::wip::WipMountRegistry` is the Host-owned namespace, Object, and operation registry. A provider requests a root namespace with `allocate_namespace(owner, namespace)`; the owner is retained as Host metadata and is not inserted into the public path. It then mounts the collection Object directly at `/<namespace>` and may install a bounded direct-child resolver. Features do not appear as intermediate Objects.
|
||||
|
||||
- Routes must be canonical absolute WIP paths.
|
||||
Object resolution and operations are separate contracts. One mounted `WipProjection` owns a static Object route and its initial operations. Another Feature may add operations with `contribute_operations` without replacing that Object. Dynamic families likewise keep one `WipDynamicItemResolver`, while `contribute_dynamic_operations` supplies disjoint handlers for every resolved item without a second resolver. The Host merges only contributions with the same interface format, documentation, and type declarations; duplicate operation names, inconsistent interfaces/validators, missing targets, duplicate namespace owners, and unrelated route claims fail deterministically at registration. The merged interface validator changes with the effective operation set, so stale Known Space cannot authorize a newly contributed operation.
|
||||
|
||||
- Routes must be canonical absolute WIP paths, and allocated namespaces are one lowercase root segment.
|
||||
- Object names must match the final route segment.
|
||||
- A projected object exposes exactly its declared interface.
|
||||
- Unrelated duplicate routes and conflicting interface descriptors or validators fail startup.
|
||||
- Object existence and resolution have one owner; operation contributors cannot remount or substitute the Object.
|
||||
- Multiple Features may contribute disjoint operations to the same Object interface.
|
||||
- Unrelated duplicate routes, duplicate operation names, and conflicting interface shapes fail startup.
|
||||
- A bounded dynamic mount may resolve exactly one item segment below an already mounted native collection; deeper paths never fall through to the resolver.
|
||||
- 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.
|
||||
|
||||
`WipInspect` renders the complete descriptor, including descriptor-local named declarations and recursive record, list, enum, and union shapes with required flags and declaration documentation. The unit samples `mount_collision_and_native_replacement_are_explicit` and `native_projection_preserves_descriptor_and_decodes_typed_arguments_end_to_end` demonstrate independent native registration, deterministic replacement, collision rejection, complete descriptor inspection, and a descriptor-typed native invocation.
|
||||
`WipInspect` 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:
|
||||
|
||||
| Historical route | Canonical route |
|
||||
| --- | --- |
|
||||
| `/features/ticket/tickets[/<reference>]` | `/tickets[/<reference>]` |
|
||||
| `/features/objective/objectives[/<reference>]` | `/objectives[/<reference>]` |
|
||||
| `/features/merge-request/merge-requests[/<reference>]` | `/merge-requests[/<reference>]` |
|
||||
|
||||
The built-in Repository/Workdir reference provider allocates `/repositories`, `/workdirs`, and `/workdir-attachments` using this contract; `manage-workdir` contributes operations rather than owning another Object. See [Repository, Workdir and attachment WIP projection](workdir-wip-projection.md) for identity encoding, reference/management permissions, attachment lifetime safety, and first-Workspace discovery. `/checkouts` content projection remains a separate provider.
|
||||
|
||||
### Registering a subsequent provider
|
||||
|
||||
1. Allocate `allocate_namespace("repository", "repositories")`. The returned `WipNamespaceRoute::root()` is `/repositories`; the owner is independent of any Feature registration name.
|
||||
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.
|
||||
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.
|
||||
|
||||
## Authority and execution
|
||||
|
||||
Discovery is not authority. The Worldspace contains only the tools already registered from enabled Features and the Worker's current execution context. Calling a compatibility operation:
|
||||
Discovery is not authority. Object publication, operation implementation, target capability, and subject permission are independent checks. An Object may remain discoverable through an enabled read provider when a management Feature contributes no operations; conversely, publishing an operation never bypasses the target's current capability or the subject's current permission. Every handler re-evaluates permission at call time, so revocation after discovery is rejected before provider dispatch. Feature enablement selects implementations and does not itself grant read or mutation authority.
|
||||
|
||||
The Worldspace contains only the operations registered from enabled Features and the Worker's current execution context. Calling a compatibility operation:
|
||||
|
||||
1. resolves the exact mounted route;
|
||||
2. verifies object and interface membership and validators;
|
||||
@@ -85,6 +111,8 @@ The stateful `wip-client::Client` is owned by one Worker WIP runtime. Sessions a
|
||||
|
||||
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. `WipDiscover(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.
|
||||
|
||||
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.
|
||||
|
||||
## Errors, cancellation, and retries
|
||||
|
||||
The adapter keeps these outcomes distinct:
|
||||
@@ -96,6 +124,8 @@ The adapter keeps these outcomes distinct:
|
||||
- **disconnected/timeout after dispatch**: `wip-client` records an unknown outcome;
|
||||
- **operation outcome unknown**: an executing provider fails without a rollback/non-execution guarantee, a response cannot be completed after dispatch, or the call future is force-closed.
|
||||
|
||||
Cooperative cancellation is scoped to the active execution's selected operation and exact resolved handler instance. Static/dynamic dispatchers forward `cancel_operation` only to that operation's provider, once per cancellation request, never to unrelated contributors or every alias backed by a shared handler. The runtime pins the dispatcher used for execution rather than resolving the Object again on cancellation, since dynamic resolvers may return stateful instances. Providers may implement `cancel_operation` for operation-specific control or the shared `cancel` default. Terminal completion or a dropped execution future releases the active binding; unknown/finished execution IDs do not invoke any provider. A cancellation request is not itself terminal confirmation.
|
||||
|
||||
An unknown mutating outcome must never be retried automatically. The model must inspect external state or ask for operator guidance. Retrieval failures may be explicitly refreshed.
|
||||
|
||||
## Measurement
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
# Subject / Memory information audit (T-692)
|
||||
|
||||
## Decision and scope
|
||||
|
||||
The previous Subjects index exposed `Store revision` alongside identity, state and
|
||||
update time; Subject detail led with technical metadata and raw surface states.
|
||||
These numbers require implementation knowledge before they help a user choose a
|
||||
Subject or understand what is available. The revised hierarchy starts with
|
||||
identity, connection, committed records and generated-context availability.
|
||||
|
||||
This is a presentation change, not a change to storage, freshness comparisons,
|
||||
permissions, generation, or Worker history. T-688's ordinary Worker launch and
|
||||
T-689's independent Subject creation remain the actual operation paths. T-693
|
||||
owns editable user-managed behavior: that content must remain distinct from this
|
||||
page's context generated from committed Memories. A successful read or a current
|
||||
surface does not attest what is already in any running Worker's history.
|
||||
|
||||
## Field classification and before/after priorities
|
||||
|
||||
| Information | Classification and reason | Presentation decision |
|
||||
| --- | --- | --- |
|
||||
| Subject role and ID | Normal identification. Similar or identical roles need a stable identifier for selection and comparison. | Keep role as heading and the complete wrapping ID visible in index and detail. |
|
||||
| Subject active/retired state | Normal operation decision: whether a new Worker connection can use the Subject. | Replace raw `active` with `Available`; keep `Retired`. Detail explains connection eligibility, not an assertion that a Worker is running. |
|
||||
| Current Worker | Normal connection decision, derived from the existing Backend singleton projection. | Promote `Connected` / `Not connected` and display name. Do not infer ownership from store revision or claim all Workers received current Memory. Worker start remains the ordinary launch form. |
|
||||
| Committed-Memory presence | Normal reading decision, independent from surface generation or candidates. | Show `Available` / `None` only on the successful first bounded page. On later pages say `N on this page`; errors say `Unavailable`. Never infer counts from revision or scan all pages. |
|
||||
| List counts | Normal navigation context, not a store-wide statistic. | Label `N shown` and `more available`, preserving existing bounded cursor pagination. |
|
||||
| Resident availability | Normal context decision. A missing surface is not missing committed Memory. | `Ready to use`, `Ready, no context`, `Not generated`, `Needs refresh`, `Generation failed`, and request `Unavailable` are distinct. These describe the current generated store artifact, not content truth or Worker-history propagation. |
|
||||
| Resident body and generated time | Normal content/read freshness context. | Keep the shared Markdown renderer, generated date and exact snapshot reference count. Ready-empty explains that a valid snapshot has no body; stale/failed do not display a partial or old snapshot. |
|
||||
| Subject store revision | Diagnostic only: internal committed-Memory change number, not record count, schema version or quality score. | Remove it from the index's normal columns. Retain the exact value under detail's `Technical details`, with its meaning explained. Backend comparisons are untouched. |
|
||||
| Subject update time | Secondary metadata; not a context-injection or generation completion timestamp. | Label `Last changed`; on detail put it with Subject diagnostics rather than competing with the availability summary. |
|
||||
| Snapshot ID and built-from revision | Diagnostic correlation, distinct from per-Memory revisions. | Retain under `Surface sources and diagnostics`, labelled `Generated from Subject revision` and explained. |
|
||||
| Surface Memory references | Detailed audit/reachability. | Preserve reference IDs, immutable revision values and Memory links in the disclosure. |
|
||||
| Memory claim, kind, lifecycle state, excerpt and body | Normal content decision. Active, resolved and retracted are not interchangeable. | Retain list scanning and body reading. Keep the Markdown renderer and current/historical distinction. |
|
||||
| Individual Memory revision and history | Detailed content comparison, also useful for identifying a selected version. | Explicit `Memory revision` labels, separate from Subject counters. Preserve immutable history, selected revision links and revision pagination. |
|
||||
| Candidate provenance, evidence, origin, source refs and derivations | Detailed audit, required to understand why a record exists. | Retain IDs, ranges, summaries, excerpts, origins and derived-revision links. Counts say `shown` except where the API provides exact per-candidate totals. Preserve body and evidence continuation links. |
|
||||
| Raw field names / duplicated general revision terminology | Unnecessary in the normal hierarchy; multiple unrelated counters are misleading. | Replace bare revision labels and raw surface enums with purpose-specific labels. Do not delete API fields, stored information, diagnostics or their detailed access. |
|
||||
|
||||
No diagnostic datum was removed from Subject detail, surface detail or Memory
|
||||
provenance/history. The index no longer shows a store revision, but the exact
|
||||
value remains one click away in Subject detail. No invented regeneration,
|
||||
editing or recovery action was added; `Needs refresh` does not mean an update job
|
||||
is running. Creation still creates only a Subject, and selection still uses the
|
||||
existing ordinary launch contract.
|
||||
|
||||
## Candidate-only verification
|
||||
|
||||
Candidates are not committed records and are not an input to this page. The
|
||||
Subject loader performs just three bounded reads: Subject, resident surface and
|
||||
`/memories?limit=100[&cursor=...]`. It does not read or count staging records.
|
||||
|
||||
The existing real-store regression
|
||||
`subjektiv::tests::candidate_decisions_reject_conflicts_and_roll_back_partial_writes`
|
||||
stages a candidate and attempts an invalid apply. It asserts the candidate has no
|
||||
resolution and the committed Memory list remains empty. The component regression
|
||||
`candidate-only Subjects show no committed Memories, not an inferred candidate count`
|
||||
uses that read projection (store revision 0, ungenerated surface, empty successful
|
||||
committed list) and checks `None`, `No committed Memories yet.`, `Not connected`
|
||||
and `Not generated`, with no resident body. Thus a staged candidate does not turn
|
||||
into a committed-Memory count or a claim that context has been generated.
|
||||
|
||||
The store test proves the persistence boundary; the component test proves the
|
||||
rendering of its public projection. These are separate boundary tests, **not** a
|
||||
live browser-to-Backend candidate-creation E2E. The existing `ungenerated` capture
|
||||
represents the same visible projection, but does not itself stage a candidate.
|
||||
|
||||
## Visual review and validation evidence
|
||||
|
||||
The restored implementation is in `fbb09e65` and `4cf6c130`; this report/test
|
||||
supplement does not change rendered markup, styling, copy or data contracts.
|
||||
|
||||
- Scenarios: `tools/web-ux/scenarios/memory-subjects-{light,dark}.json`.
|
||||
- Before: `target/web-ux/t-692-before-{light,dark}` at `cc979874`.
|
||||
- After: `target/web-ux/t-692-final2-{light,dark}` at clean `4cf6c130`.
|
||||
- Comparisons: `target/web-ux/t-692-final2-{light,dark}-comparison`.
|
||||
- Browser interactions: `target/web-ux/t-692-browser-interactions`.
|
||||
- Persona: synthetic Workspace fixture; permitted creation and intentional
|
||||
permission-rejection responses. No real account or private store data used.
|
||||
- Viewports: 1440, 768, 390 and 320px; light and dark themes.
|
||||
- States: connected/unconnected, active/retired, successful empty lists, ready
|
||||
long Markdown, ready-empty, ungenerated, stale, failed, unavailable HTTP503,
|
||||
create form and create permission error; expanded technical disclosures.
|
||||
- The takeover implementer personally inspected individual before/after images
|
||||
for index at 768px, representative detail at desktop/mobile and Memory detail,
|
||||
then ready-empty mobile, ungenerated narrow, stale desktop, failed mobile,
|
||||
endpoint error at 320px, mobile surface sources, compact Subject diagnostics
|
||||
and mobile permission error. Oversized contact sheets were rejected by the
|
||||
image provider; individual viewport PNGs were inspected instead.
|
||||
- Findings/result: primary state groups replace counters without losing IDs or
|
||||
document access; long IDs wrap, status is textual rather than color-only,
|
||||
mobile groups stack, diagnostics remain readable, and error state regions stay
|
||||
separate. No new visual defect identified. **Pass for the audited scope.**
|
||||
- Final bundles contain 64 captures each. `completed-with-errors` is expected:
|
||||
intentional creation HTTP403, endpoint HTTP503/associated aborted requests,
|
||||
and the deliberately failed surface's alert are retained as evidence. Healthy
|
||||
capture states have empty error arrays; this is not a blanket claim that all
|
||||
captures were error-free. Review-context diagnostics are empty.
|
||||
- The focused production-shell browser test proves main-owned vertical scrolling
|
||||
with wheel/keyboard/touch, 320px/mobile shell behavior, no page-wide overflow,
|
||||
local table/code scroll, Markdown safety, creation/launch separation, bounded
|
||||
pagination and Memory/source/revision reachability.
|
||||
|
||||
Independent review at source `4cf6c130` ran root `cargo check`,
|
||||
`cargo fmt --all -- --check`, diff hygiene, Web check (0 errors/warnings), 12
|
||||
Memory API tests, 452 full Web unit tests, 134 component tests (8 Memory tests),
|
||||
production build, the focused production-shell browser test (1), and Web-UX unit
|
||||
tests (16), all passing.
|
||||
|
||||
The takeover implementer then validated this report/test supplement with:
|
||||
|
||||
- `cargo test -p yoi-workspace-server --lib candidate_decisions_reject_conflicts_and_roll_back_partial_writes`: 1 passed.
|
||||
- Root `cargo check`, `cargo fmt --all -- --check`, and `git diff --check HEAD`: passed.
|
||||
- Targeted Memory component tests: 9 passed, including the added candidate-only projection test.
|
||||
- Web `deno task check`: 0 errors/warnings; `deno task test`: 452 passed;
|
||||
`deno task test:component`: 135 passed.
|
||||
- Scoped `deno fmt --check` on the changed TypeScript test: passed.
|
||||
- JSON audit of both final2 bundles: 64 captures each, exact clean source
|
||||
`4cf6c130`, and no errors outside the deliberate permission/error/failed routes.
|
||||
|
||||
The supplement changes only a document and a test, so it does not require new
|
||||
rendered-UI captures. Rereview records and the final approved Ticket handoff link
|
||||
this report to the new exact source.
|
||||
|
||||
Known non-blocking validation diagnostics: component runs emitted incidental
|
||||
localhost:3000 connection-refused messages while passing; the production build
|
||||
warned about a large chunk. A broader Web-UX typecheck fails in unchanged
|
||||
`tools/web-ux/src/processes.ts:44` on a `TextDecoderStream` generic incompatibility;
|
||||
this report does not claim that broad check passed.
|
||||
|
||||
No live-Backend browser interactions, real Worker model-request propagation,
|
||||
regeneration, or server/runtime process E2E were performed. No Rust production
|
||||
crate changed in T-692; the supplemental store test exercises an existing
|
||||
contract without changing that contract. Backend counters, comparison logic,
|
||||
storage schema and feature behavior remain intact.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Review finding severity contract mismatch during T-697
|
||||
|
||||
The independent Reviewer completed source/requirement analysis and validation,
|
||||
then its one `ReviewMergeRequest` submission was rejected with HTTP 422 because
|
||||
it used severity `medium`. The tool exposed a free-form string, while Backend
|
||||
validation accepts only `blocker`, `major`, `minor`, or `note`. No verdict was
|
||||
recorded by that failed call. The child preserved the source and reported the
|
||||
blocked submission rather than loop-retrying a mutation.
|
||||
|
||||
The parent inspected the committed review session and fresh MR authority,
|
||||
confirmed the same request/source/Ticket snapshot with no verdict, and submitted
|
||||
a fresh child turn to correct the input contract. The Reviewer independently
|
||||
selected supported severities and recorded `request_changes` successfully on
|
||||
the same MR. No alternate token/context, CLI/storage write, source movement or
|
||||
replacement MR was used to compensate for the rejection.
|
||||
|
||||
Suggested improvement: expose finding severity as the typed Backend enum in the
|
||||
LLM tool schema, and document allowed values in the Reviewer prompt. Rejecting
|
||||
an unadvertised enum after a costly review should not prevent durable findings
|
||||
from reaching the MR. This report is tool feedback, not a T-697 product
|
||||
constraint or a request to alter review judgments.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Reviewer verdict のvalidation rejectionとone-call制約
|
||||
|
||||
## 確認した事実
|
||||
|
||||
T-703のMR `01a10b3b-87ec-7093-b0c4-a00a78095695`、source
|
||||
`3174142bd1314fe34c5de7b6a66654ff1c2a8af2` の独立ReviewerはRestoreとno-op
|
||||
attention checkの競合を見つけ、`ReviewMergeRequest`でrequest_changesを提出しようとした。
|
||||
severityに`medium`を指定したためHTTP 422となった。Backendの許容値は
|
||||
`blocker` / `major` / `minor` / `note` だった。
|
||||
|
||||
親の`ShowMergeRequest`再読でthreadはReviewRequested seq2までであり、verdictが
|
||||
永続化されていないことを確認した。Reviewerは「ReviewMergeRequestを正確に一度だけ
|
||||
呼ぶ」という指示に従い、validation rejection後も再提出を行わなかった。親のfollow-upでも
|
||||
同じ境界を報告したため、再提出を強制せずReviewerを停止した。
|
||||
|
||||
## 障壁
|
||||
|
||||
正しいBackend拒否を迂回すべきではない一方、mutationが行われていない入力validation失敗が
|
||||
一回限りの提出枠を消費する扱いだと、レビュー済みの指摘がMR authorityに残らずpendingになる。
|
||||
セッションでの報告をverdictや承認の代わりにはできない。
|
||||
|
||||
## 改善案(このTicketの実装対象ではない)
|
||||
|
||||
- Reviewer-facing tool schemaにseverityのBackend enumを明示し、不正値を入力時に防ぐ。
|
||||
- one-call指示について「一度のdurable verdict」と「validationで拒否された呼出」を区別できるか
|
||||
設計上判断する。無制限再提出や記録済みverdictの変更を認める提案ではない。
|
||||
- mutationなし/retry可否をtyped errorとして返せると、親とReviewerの双方が推測なしに扱える。
|
||||
|
||||
T-703では元のMR/source selectorを保持し、指摘を修正したcommitを通常pushした後、fresh
|
||||
exact-source reviewで修正内容とその証拠をMRに記録する。未記録のverdictを承認扱いしない。
|
||||
@@ -0,0 +1,18 @@
|
||||
# Reviewer SubWorkerがreview開始前に停止する
|
||||
|
||||
## 状況
|
||||
|
||||
T-698の公開済みMerge Requestに対して、`builtin:reviewer`を指定し、対象Ticket/Merge Request、writable delegated scope、command grantを明示してReviewer SubWorkerを3回起動した。
|
||||
|
||||
いずれも`review_requested` eventは正しいsource refとTicket revisionを記録したが、SubWorkerは直後に`Stopped`となった。session observationには最初のuser taskだけが存在し、assistant output、tool call、typed review verdictは記録されなかった。Merge Request threadにもapprove/request_changesは追加されなかった。
|
||||
|
||||
## 障壁
|
||||
|
||||
CoderはReviewer approvalを代行できず、親Workerには`ReviewMergeRequest` authorityがないため、実装・公開・検証が完了していてもfresh approvalを取得できない。同じ入力を再送するだけでは診断情報が増えず、review requestだけが複数残る。
|
||||
|
||||
## 改善案
|
||||
|
||||
- Reviewer起動がmodel run前に停止した場合、停止理由を親へ構造化して通知する。
|
||||
- `review_requested`を記録した後にReviewer sessionの開始に失敗した場合、request eventと失敗eventを関連付け、未解決reviewとして明示する。
|
||||
- profile/provider初期化、review worktree準備、capability bindingのどの段階で失敗したかを、credentialやhost pathを露出しないbounded diagnosticとして提供する。
|
||||
- 同一sourceへの再試行時は、先行Reviewerが一度も実行されていないことを識別できるようにする。
|
||||
@@ -0,0 +1,33 @@
|
||||
# SubWorker cwd attachment-root ambiguity during T-697
|
||||
|
||||
## Observed barrier
|
||||
|
||||
A delegated backend investigation was spawned with `cwd=crates/workspace-server`
|
||||
and explicit writable rules for both `crates/workspace-server` and
|
||||
`crates/server-api`, plus repository-root read access. The child reported that
|
||||
its available attachment exposed only the workspace-server crate; its observed
|
||||
file reads used `src/server.rs`/`src/lib.rs` and it could not access server-api.
|
||||
It also had no `ShowTicket` or parent-notification tool, despite the parent
|
||||
having typed Ticket authority. No implementation changes were made by that child.
|
||||
|
||||
The parent inspected the committed child session, released the idle child, and
|
||||
respawned at the repository root with the same delegated write boundaries and
|
||||
an explicit summary of the authoritative Ticket requirements. That child could
|
||||
then implement the cross-crate API boundary. No filesystem capability rejection
|
||||
was worked around through another write path.
|
||||
|
||||
## Suggested improvement
|
||||
|
||||
The advertised SubWorker `cwd` contract says that it changes only the tool
|
||||
working directory, not attachment roots. Show the effective attachment aliases,
|
||||
logical roots and readable/writable scopes explicitly to the child and parent,
|
||||
and test cross-crate reads/writes for a non-root cwd. If cwd intentionally
|
||||
narrows or rebases an attachment, document that instead of presenting it as
|
||||
only a command default. A denied/inaccessible sibling diagnostic should identify
|
||||
the effective logical attachment root without disclosing unauthorized paths.
|
||||
|
||||
Also expose which typed domain and parent-messaging tools will be available
|
||||
before spawning. Delegated implementation requires authoritative requirements;
|
||||
where Ticket reads are unavailable, the parent must deliberately provide the
|
||||
bounded contract rather than assume the child can recover it by ID. This report
|
||||
records tool ergonomics only; it is not a new T-697 product requirement.
|
||||
Reference in New Issue
Block a user