refactor(api): expose traced remote namespaces

This commit is contained in:
imccyu
2026-08-07 18:28:30 +08:00
parent 146097368b
commit d6ffd87c5f
38 changed files with 566 additions and 492 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/api-gateway.md
api-gateway.md: 090758d58306d5ea806567f0de710a1c1f5ed747
api-gateway.zh.md: 9d7286b6b86918f3bc1e7a6cdd9bdf04447abc57
api-gateway.md: 90aa661cc86a4f419e173560c55511c969182990
api-gateway.zh.md: 6fcbb562b204e71d00833042ee0632bda0217940

View File

@@ -6,7 +6,7 @@ This is the current-state reference for the TypeRT API Gateway. It describes how
## Programming model
Business services use `@Remote` or `@RemoteContext` to select the methods exposed to the Client. Unmarked methods do not enter the generated Client types or runtime contributions and cannot be called through `ctx.api`.
Business services use `@Remote` or `@RemoteContext` to select the methods exposed to the Client. Unmarked methods do not enter the generated Client types or runtime contributions and cannot be called through `ctx.remote`.
`@Remote` denotes calling a Cordis service registered on the root Host Context. Complex Host objects cannot cross the wire directly; the business package must declare their association with a wire identity through `TypeRTLookupMap` and register a default resolution provider with `ctx.typert.lookups` at runtime. For example, an `Agent` parameter named `agent` in the Host signature produces an `agentId` wire field, and the Gateway resolves that id to a Host object before invoking the business method. Host composition can use `ctx.typert.lookups.configure()` to override the resolution policy for a lookup key without changing the parameter name, wire field, or canonical type symbol owned by the business package.
@@ -55,7 +55,7 @@ export class GoalService extends GatewayService {
Remote methods may return a value synchronously or return a Promise. For cooperative cancellation, the final parameter in the Host signature must be `signal: AbortSignal` using the global type; it is recorded in the descriptor instead of entering `args`, while the generated Client method accepts an optional final `AbortSignal`.
The Client uses concrete functions on ordinary objects, not a JavaScript Proxy. Direct Remotes appear under `ctx.api.<namespace>`; when an `@Remote` method has exactly one lookup parameter and a same-named `TypeRTContextMap` uses the same wire identity, the generator also projects the method without that identity parameter onto the corresponding scoped Context. `@RemoteContext` generates only the scoped invocation interface.
The Client uses concrete functions on ordinary objects, not a JavaScript Proxy. Direct and scoped calls appear under `ctx.remote.<namespace>` and `agentCtx.remote.<namespace>`. Each namespace is a traced Cordis child Service registered as `remote.<namespace>`; the Client assembly mounts contributions through `ctx.remote.$mount()`, consumers inject both `remote` and the namespace Service they call, and the namespace unloads after its last method is withdrawn. When an `@Remote` method has exactly one lookup parameter and a same-named `TypeRTContextMap` uses the same wire identity, the generated scoped signature omits that identity parameter. `@RemoteContext` generates only the scoped invocation interface.
```ts
import type { SessionId } from '@deepseek-ai/dsh-session/types'
@@ -67,13 +67,13 @@ declare const ctx: Context
declare const agentCtx: AgentContext
declare const agentId: SessionId
await ctx.api.goals.create(agentId, { objective: 'ship it' })
await agentCtx.goals.create({ objective: 'ship it' })
await ctx.remote.goals.create(agentId, { objective: 'ship it' })
await agentCtx.remote.goals.create({ objective: 'ship it' })
```
Client applications assemble only `@deepseek-ai/dsh-api-remotes`. That package imports the `/remote` subpaths of selected business packages as runtime values, mounts their contributions on `ctx.api`, and re-exports the declaration merges from the same files. Adding a Host Remote package is an explicit choice by the Client composition owner; business components do not need to load the TypeRT Gateway or the business package's Remote JS separately.
Client applications assemble only `@deepseek-ai/dsh-api-remotes`. That package imports the `/remote` subpaths of selected business packages as runtime values, mounts their contributions through `ctx.remote.$mount()`, and re-exports the declaration merges from the same files. Adding a Host Remote package is an explicit choice by the Client composition owner; business components do not need to load the TypeRT Gateway or the business package's Remote JS separately.
A future TUI can assemble the same React-independent `api-remotes` and `ctx.api` contract, so the Host methods visible to it are likewise limited to the Remote methods selected at generation time. This document does not define or implement the TUI composition.
A future TUI can assemble the same React-independent `api-remotes` and `ctx.remote` contract, so the Host methods visible to it are likewise limited to the Remote methods selected at generation time. This document does not define or implement the TUI composition.
## Component responsibilities
@@ -84,11 +84,11 @@ A future TUI can assemble the same React-independent `api-remotes` and `ctx.api`
| Host | `@deepseek-ai/dsh-typert-registry` and Loader | Places generated Host descriptors, schemas, and business-package registrations in `ctx.typert`, and holds lookup and Context providers |
| Host | `@deepseek-ai/dsh-api-remotes` | Owns the application Agent/Session identity policy and configures the corresponding TypeRT lookups |
| Host | `@deepseek-ai/dsh-api-gateway` | Provides `ctx.typertGateway`, claims Remote endpoints, resolves objects or Contexts, invokes live Cordis services, and validates boundaries |
| Client | `@deepseek-ai/dsh-api-gateway/client` | Provides `ctx.api`, mounts generated descriptors as concrete methods, and initiates, validates, and cancels calls through the Connection |
| Client | `@deepseek-ai/dsh-api-gateway/client` | Provides `ctx.remote` and `remote.<namespace>` child Services, mounts generated descriptors as concrete methods, and initiates, validates, and cancels calls through the Connection |
| Client | `@deepseek-ai/dsh-api-remotes/client` | Explicitly selects and mounts the `/remote` contributions allowed by the application and brings the corresponding declaration merges into business code |
| Both | `@deepseek-ai/dsh-client-connection` | Provides the RPC carrier, request correlation, trust boundary, cancellation, response envelope, and current `/api` HTTP bridge |
The API Gateway package owns the Host dispatcher and Client API as peer entries, but the two builds never enter the same `ts.Program`. The Host entry does not import the Client Cordis `Context` merge, and the Client entry does not import the Host Gateway service.
The API Gateway package owns the Host dispatcher and Client Remote endpoint as peer entries, but the two builds never enter the same `ts.Program`. The Host entry does not import the Client Cordis `Context` merge, and the Client entry does not import the Host Gateway service.
## Strict generation pipeline
@@ -106,13 +106,13 @@ Each contributing business package writes generated files to its own `lib/` dire
Business packages expose the Host Loader entry through `./typert` and the Host-for-Client entry through `./remote`. The generator also validates these package exports and published-file lists; it generates artifacts only for explicit contribution packages that provide the corresponding entry.
Parameter names in Remote Client declarations come from wire fields, while parameter and return types reference Client-safe types exported by the original business package. The declaration map resolves the generated property behind `ctx.api.goals.create` back to the Host source method marked with `@Remote`, so editors that support declaration maps can navigate from a Client call to the real implementation instead of stopping at the generated `.d.ts`.
Parameter names in Remote Client declarations come from wire fields, while parameter and return types reference Client-safe types exported by the original business package. The declaration map resolves the generated property behind `ctx.remote.goals.create` back to the Host source method marked with `@Remote`, so editors that support declaration maps can navigate from a Client call to the real implementation instead of stopping at the generated `.d.ts`.
Strict analysis requires a Remote to be a public, non-static instance method with a concrete implementation. The method cannot be generic; parameters must be required, named simple identifiers and cannot use destructuring, default values, rest parameters, or optional parameters. TypeRT generates strict schemas for ordinary JSON-representable types; complex objects such as workspace classes must have a unique `TypeRTLookupMap` declaration. Lookup and Context packages are responsible for both static declaration merges and runtime provider registration; if either side is missing, the build or earliest resolvable runtime boundary fails.
## Runtime invocation
Remote and API Proxy currently share the Connection's `/api` route; there is no separate `/api2` server or second Connection. The Client API calls `connection.rpc.call('/api', '<namespace>/<method>', { args }, signal)`; the current HTTP carrier maps this to `POST /api/<namespace>/<method>`, with a payload containing only a named `args` object.
Remote and API Proxy currently share the Connection's `/api` route; there is no separate `/api2` server or second Connection. The Client Remote calls `connection.rpc.call('/api', '<namespace>/<method>', { args }, signal)`; the current HTTP carrier maps this to `POST /api/<namespace>/<method>`, with a payload containing only a named `args` object.
The Connection performs the unified trust check for `/api` before the HTTP bridge, then dispatches inside the shared FetchHandler in interceptor order. The TypeRT Gateway claims only two-segment endpoints that have a strict descriptor or active SRC marker; unclaimed requests fall back to the existing API Proxy. The Connection owns transport, RPC ids, response envelopes, and request cancellation, while the Gateway owns only the Remote data protocol and business dispatch. Replacing the Connection carrier in the future does not require changes to Remote descriptors or the Client programming interface.
@@ -128,7 +128,7 @@ When the Host starts from source through `node --import tsx/esm`, it does not ex
The SRC fallback parses simple parameter names from the live function. When a parameter name matches the `parameter` of a registered lookup, such as `agent` or `session`, it uses the lookup's `agentId` or `sessionId` wire field and resolves the object on the Host; other parameters are checked only for cycle-free, JSON-safe data with no special prototype. `@RemoteContext` directly uses the wire field of a registered Host Context provider. SRC does not read TypeScript types, generate Zod schemas, infer optional parameters, or support destructuring, default values, rest parameters, or duplicate parameter names.
SRC solves only dispatch for a Host process running from source. The Client does not discover decorators from the running Host, and the Client API refuses to mount SRC descriptors that lack strict codecs; its types, codecs, and Remote registration values always come from the most recently generated `lib/typert.remote-client.*` artifacts.
SRC solves only dispatch for a Host process running from source. The Client does not discover decorators from the running Host, and the Client Remote refuses to mount SRC descriptors that lack strict codecs; its types, codecs, and Remote registration values always come from the most recently generated `lib/typert.remote-client.*` artifacts.
## Development mode

View File

@@ -6,7 +6,7 @@
## 编程模型
业务 Service 通过 `@Remote``@RemoteContext` 选择对 Client 开放的方法。未标记的方法不会进入生成的 Client 类型或运行时贡献,也不能通过 `ctx.api` 调用。
业务 Service 通过 `@Remote``@RemoteContext` 选择对 Client 开放的方法。未标记的方法不会进入生成的 Client 类型或运行时贡献,也不能通过 `ctx.remote` 调用。
`@Remote` 表示调用根 Host Context 中注册的 Cordis Service。复杂的 Host 对象不能直接跨 wire 传输;业务包必须通过 `TypeRTLookupMap` 声明它与 wire identity 的关联,并在运行时向 `ctx.typert.lookups` 注册默认解析提供方。例如 `Agent` 参数在 Host 签名中名为 `agent`,生成的 wire 字段为 `agentId`Gateway 在调用业务方法前将 id 解析为 Host 对象。Host 组合可以用 `ctx.typert.lookups.configure()` 覆盖某个 lookup key 的解析策略而不改变业务包拥有的参数名、wire 字段或规范类型 symbol。
@@ -55,7 +55,7 @@ export class GoalService extends GatewayService {
Remote 方法可以同步返回或返回 Promise。若需要协作式取消Host 签名的最后一个参数必须是全局类型的 `signal: AbortSignal`;它记录在描述符中而不是进入 `args`Client 生成的方法则接受最后一个可选的 `AbortSignal`
Client 使用普通对象上的具体函数,不使用 JavaScript Proxy。直接 Remote 出现在 `ctx.api.<namespace>`当一个 `@Remote` 方法恰好有一个 lookup 参数、且同名 `TypeRTContextMap` 使用相同 wire identity 时,生成器还会把去掉该 identity 参数后的方法投影到对应作用域 Context`@RemoteContext` 只生成作用域调用界面。
Client 使用普通对象上的具体函数,不使用 JavaScript Proxy。直接调用与作用域调用分别出现在 `ctx.remote.<namespace>``agentCtx.remote.<namespace>`。每个 namespace 都是注册为 `remote.<namespace>` 的可追踪 Cordis 子 ServiceClient assembly 通过 `ctx.remote.$mount()` 挂载贡献,消费方同时注入 `remote` 与所调用的 namespace Service最后一个方法撤回后该 namespace 随即卸载。当一个 `@Remote` 方法恰好有一个 lookup 参数、且同名 `TypeRTContextMap` 使用相同 wire identity 时,生成的作用域签名会省略该 identity 参数。`@RemoteContext` 只生成作用域调用界面。
```ts
import type { SessionId } from '@deepseek-ai/dsh-session/types'
@@ -67,13 +67,13 @@ declare const ctx: Context
declare const agentCtx: AgentContext
declare const agentId: SessionId
await ctx.api.goals.create(agentId, { objective: 'ship it' })
await agentCtx.goals.create({ objective: 'ship it' })
await ctx.remote.goals.create(agentId, { objective: 'ship it' })
await agentCtx.remote.goals.create({ objective: 'ship it' })
```
Client 应用只装配 `@deepseek-ai/dsh-api-remotes`。该包以运行时值导入被选业务包的 `/remote` 子路径,并向 `ctx.api` 挂载贡献,同时重新导出相同文件中的声明合并。增加一个 Host Remote 包是 Client 组合所有者的显式选择;业务组件不需要分别加载 TypeRT Gateway 或业务包的 Remote JS。
Client 应用只装配 `@deepseek-ai/dsh-api-remotes`。该包以运行时值导入被选业务包的 `/remote` 子路径,通过 `ctx.remote.$mount()` 挂载贡献,同时重新导出相同文件中的声明合并。增加一个 Host Remote 包是 Client 组合所有者的显式选择;业务组件不需要分别加载 TypeRT Gateway 或业务包的 Remote JS。
未来的 TUI 可以装配同一个不依赖 React 的 `api-remotes``ctx.api` 契约,因此它能看到的 Host 方法同样只限于生成时选择的 Remote 方法。本文不定义或实现 TUI 组合。
未来的 TUI 可以装配同一个不依赖 React 的 `api-remotes``ctx.remote` 契约,因此它能看到的 Host 方法同样只限于生成时选择的 Remote 方法。本文不定义或实现 TUI 组合。
## 组件职责
@@ -84,11 +84,11 @@ Client 应用只装配 `@deepseek-ai/dsh-api-remotes`。该包以运行时值导
| Host | `@deepseek-ai/dsh-typert-registry` 与 Loader | 把生成的 Host 描述符、schema 及业务包注册项放入 `ctx.typert`,并持有 lookup 与 Context 提供方 |
| Host | `@deepseek-ai/dsh-api-remotes` | 负责应用的 Agent/Session 身份策略,并配置对应的 TypeRT lookup |
| Host | `@deepseek-ai/dsh-api-gateway` | 提供 `ctx.typertGateway`,认领 Remote endpoint解析对象或 Context调用实时 Cordis Service 并校验边界 |
| Client | `@deepseek-ai/dsh-api-gateway/client` | 提供 `ctx.api`,把生成的描述符挂成具体方法,并通过 Connection 发起、校验和取消调用 |
| Client | `@deepseek-ai/dsh-api-gateway/client` | 提供 `ctx.remote``remote.<namespace>` 子 Service,把生成的描述符挂成具体方法,并通过 Connection 发起、校验和取消调用 |
| Client | `@deepseek-ai/dsh-api-remotes/client` | 显式选择并挂载本应用允许使用的 `/remote` 贡献,向业务代码带入对应的声明合并 |
| 双侧 | `@deepseek-ai/dsh-client-connection` | 提供 RPC carrier、请求关联、信任边界、取消、响应 envelope 与当前 `/api` HTTP bridge |
API Gateway 包同时拥有 Host dispatcher 与 Client API 两个对等入口,但两侧构建不会进入同一个 `ts.Program`。Host 入口不导入 Client 的 Cordis `Context` 合并Client 入口也不导入 Host Gateway 服务。
API Gateway 包同时拥有 Host dispatcher 与 Client Remote endpoint 两个对等入口,但两侧构建不会进入同一个 `ts.Program`。Host 入口不导入 Client 的 Cordis `Context` 合并Client 入口也不导入 Host Gateway 服务。
## 严格生成链路
@@ -106,13 +106,13 @@ API Gateway 包同时拥有 Host dispatcher 与 Client API 两个对等入口,
业务包通过 `./typert` 暴露 Host Loader 入口,通过 `./remote` 暴露 Host-for-Client 入口。生成器同时校验这些 package export 及发布文件清单;只有具备相应入口的显式贡献包才会生成产物。
Remote Client 声明中的参数名来自 wire 字段,参数和返回类型则引用原业务包导出的 Client-safe 类型。声明 map 把 `ctx.api.goals.create` 最终解析到的生成属性映射到带 `@Remote` 的 Host 源方法,因此支持 declaration-map 的编辑器可以从 Client 调用跳到真实实现,而不是停在生成的 `.d.ts`
Remote Client 声明中的参数名来自 wire 字段,参数和返回类型则引用原业务包导出的 Client-safe 类型。声明 map 把 `ctx.remote.goals.create` 最终解析到的生成属性映射到带 `@Remote` 的 Host 源方法,因此支持 declaration-map 的编辑器可以从 Client 调用跳到真实实现,而不是停在生成的 `.d.ts`
严格分析要求 Remote 是公开、非静态、有具体实现的实例方法。方法不能是泛型参数必须是具名且必填的简单标识符不能使用解构、默认值、rest 或可选参数。可 JSON 表示的普通类型由 TypeRT 生成严格 schema工作区 class 等复杂对象必须具有唯一的 `TypeRTLookupMap` 声明。lookup 与 Context 包同时负责静态声明合并和运行时提供方注册,缺少任一侧都会在构建或最早可解析的运行时边界报错。
## 运行时调用
当前 Remote 与 API Proxy 共用 Connection 的 `/api` 路由,不存在独立 `/api2` server 或第二套 Connection。Client API 调用 `connection.rpc.call('/api', '<namespace>/<method>', { args }, signal)`;当前 HTTP carrier 对应 `POST /api/<namespace>/<method>`payload 只包含一个具名 `args` 对象。
当前 Remote 与 API Proxy 共用 Connection 的 `/api` 路由,不存在独立 `/api2` server 或第二套 Connection。Client Remote 调用 `connection.rpc.call('/api', '<namespace>/<method>', { args }, signal)`;当前 HTTP carrier 对应 `POST /api/<namespace>/<method>`payload 只包含一个具名 `args` 对象。
Connection 在 HTTP bridge 之前执行 `/api` 的统一信任检查,再在共享 FetchHandler 内按 interceptor 顺序分发。TypeRT Gateway 只认领存在严格描述符或活跃 SRC marker 的两段式 endpoint未认领的请求回退到既有 API Proxy。Connection 拥有传输、RPC id、响应 envelope 和 request cancellationGateway 只拥有 Remote 数据协议和业务分发。未来替换 Connection carrier 不要求改变 Remote 描述符或 Client 编程界面。
@@ -128,7 +128,7 @@ Host 通过 `node --import tsx/esm` 从源码启动时不会执行 TypeRT 编译
SRC 回退从运行中函数解析简单参数名。参数名与某个已注册 lookup 的 `parameter` 相同,例如 `agent``session`,就使用其 `agentId``sessionId` wire 字段并在 Host 解析对象;其他参数只检查值是否为无循环、无特殊 prototype 的 JSON-safe 数据。`@RemoteContext` 直接使用已注册 Host Context provider 的 wire 字段。SRC 不读取 TypeScript 类型,不生成 Zod schema不推断可选参数也不支持解构、默认值、rest 或重复参数名。
SRC 只解决 Host 源码进程的分发问题。Client 不会从运行中的 Host 发现 decoratorClient API 也拒绝挂载缺少严格 codec 的 SRC 描述符其类型、codec 和 Remote 注册值始终来自最近一次生成的 `lib/typert.remote-client.*`
SRC 只解决 Host 源码进程的分发问题。Client 不会从运行中的 Host 发现 decoratorClient Remote 也拒绝挂载缺少严格 codec 的 SRC 描述符其类型、codec 和 Remote 注册值始终来自最近一次生成的 `lib/typert.remote-client.*`
## 开发模式

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/core-data-structures/typert.md
typert.md: a61ed8587833e03fd5c1246311e62a6ffaeb3bd0
typert.zh.md: 18c24018f4abd644cf35185c2bd06b6980195481
typert.md: c70e50e2fea8455eb75dfdf8c309f659ab9cb2f9
typert.zh.md: 2cd1636d4cc8dbcfa009073b4a8e1dcc8d5897e4

View File

@@ -126,10 +126,10 @@ interface TypeRTService {
}
```
Generated consumer declarations merge direct namespaces into the map inherited by `TypeRTClientApi`.
Generated consumer declarations merge direct namespaces into the map inherited by `TypeRTClientRemote`.
```ts type-equiv
/** Merge-extensible direct namespace surface generated for Client API services. */
/** Merge-extensible direct namespace surface generated for Client Remote services. */
interface TypeRTRemoteNamespaceMap {}
```
@@ -186,18 +186,18 @@ interface TypertGateway {
}
```
## Consumer API
## Consumer Remote
`ctx.api` exposes only namespaces contributed by imported `/remote` artifacts. Mounting installs the generated descriptors and concrete root/scoped methods as one fiber-owned operation; no JavaScript Proxy or Host Service type enters the consumer.
`ctx.remote` exposes only namespaces contributed by imported `/remote` artifacts. `$mount()` installs generated descriptors and concrete methods as one fiber-owned operation. Each namespace is a traced `remote.<namespace>` Cordis child Service whose lifetime spans its mounted methods; no JavaScript Proxy or Host business Service type enters the consumer.
```ts type-equiv
/** Client API capability implemented by the Gateway and consumed by Remote assemblies. */
interface TypeRTClientApi extends TypeRTRemoteNamespaceMap {
/** Client Remote capability implemented by the Gateway and consumed by Remote assemblies. */
interface TypeRTClientRemote extends TypeRTRemoteNamespaceMap {
/**
* Mount one generated Host-for-Client contribution in the caller's fiber.
* @param contribution - explicitly selected Remote package artifact.
* @returns disposer withdrawing descriptors and concrete methods together.
* @returns disposer after namespace services and concrete methods are ready.
*/
mount(contribution: TypeRTRemoteContribution): TypeRTDisposer
$mount(contribution: TypeRTRemoteContribution): Promise<TypeRTDisposer>
}
```

View File

@@ -126,10 +126,10 @@ interface TypeRTService {
}
```
生成的消费方声明会把 direct namespace 合并到 `TypeRTClientApi` 继承的 map 中。
生成的消费方声明会把 direct namespace 合并到 `TypeRTClientRemote` 继承的 map 中。
```ts type-equiv
/** Merge-extensible direct namespace surface generated for Client API services. */
/** Merge-extensible direct namespace surface generated for Client Remote services. */
interface TypeRTRemoteNamespaceMap {}
```
@@ -186,18 +186,18 @@ interface TypertGateway {
}
```
## 消费方 API
## 消费方 Remote
`ctx.api` 只暴露由已导入 `/remote` 产物贡献的 namespace。挂载会把生成的 descriptor 与具体的 root/scoped 方法作为一项由 fiber 持有的操作统一注册JavaScript Proxy 与 Host 服务类型都不会进入消费方。
`ctx.remote` 只暴露由已导入 `/remote` 产物贡献的 namespace。`$mount()` 会把生成的 descriptor 与具体方法作为一项由 fiber 持有的操作统一注册。每个 namespace 都是可追踪的 `remote.<namespace>` Cordis 子 Service其生命周期覆盖已挂载的方法JavaScript Proxy 与 Host 业务 Service 类型都不会进入消费方。
```ts type-equiv
/** Client API capability implemented by the Gateway and consumed by Remote assemblies. */
interface TypeRTClientApi extends TypeRTRemoteNamespaceMap {
/** Client Remote capability implemented by the Gateway and consumed by Remote assemblies. */
interface TypeRTClientRemote extends TypeRTRemoteNamespaceMap {
/**
* Mount one generated Host-for-Client contribution in the caller's fiber.
* @param contribution - explicitly selected Remote package artifact.
* @returns disposer withdrawing descriptors and concrete methods together.
* @returns disposer after namespace services and concrete methods are ready.
*/
mount(contribution: TypeRTRemoteContribution): TypeRTDisposer
$mount(contribution: TypeRTRemoteContribution): Promise<TypeRTDisposer>
}
```

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/development.md
development.md: f832956c4c7cbde96613a69db6c636a2246786a7
development.zh.md: 3ae70e7135ad5faee0e37d99f55cdb41373aab2c
development.md: 37bc88c7c1cfedfbe1a93e08a4cbde833ac32372
development.zh.md: a738e53cb3434d7930aa82107782a4c22aea1470

View File

@@ -62,7 +62,7 @@ Host and client stay two aggregate programs because both sides declaration-merge
Static analysis and tests resolve workspace imports through the base `paths` map to `src` and must pass on a clean tree; gates that consume built `lib/` output declare that dependency explicitly. Decision record: [solution-root note](../.agents/notes/implemented/process/2026-07-22-tsconfig-solution-root-two-aggregates.md); the tsc-first emit pipeline is the [ts-build-config note](../.agents/notes/implemented/process/2026-06-17-ts-build-config.md).
Business services declare callable methods on the Host with `@Remote` or `@RemoteContext`; the Host build generates Host-for-Client types and runtime contributions, and the Client's `api-remotes` composition loads those contributions and mounts concrete methods on `ctx.api` or the corresponding scoped Context. See [API Gateway](api-gateway.md) for the generated artifacts on both sides, their assembly relationships, the SRC development fallback, and the Web build order.
Business services declare callable methods on the Host with `@Remote` or `@RemoteContext`; the Host build generates Host-for-Client types and runtime contributions, and the Client's `api-remotes` composition loads those contributions under `ctx.remote` and scoped `agentCtx.remote` namespaces. See [API Gateway](api-gateway.md) for the generated artifacts on both sides, their assembly relationships, the SRC development fallback, and the Web build order.
If a relevant local check consumes built package output, build once first:

View File

@@ -62,7 +62,7 @@ host 与 client 保持两个聚合 program是因为两侧在相同键下以
静态分析和测试通过 base 的 `paths` 映射把工作区 import 解析到 `src`,且必须在干净树上通过;消费构建产物 `lib/` 的门禁显式声明该依赖。决策记录:[solution-root note](../.agents/notes/implemented/process/2026-07-22-tsconfig-solution-root-two-aggregates.md)tsc-first 发射管线见 [ts-build-config note](../.agents/notes/implemented/process/2026-06-17-ts-build-config.md)。
业务 Service 在 Host 使用 `@Remote``@RemoteContext` 声明可调用方法Host 构建生成 Host-for-Client 类型与运行时贡献Client 的 `api-remotes` 组合加载这些贡献并将具体方法挂载`ctx.api` 或对应的作用域 Context。两侧的生成产物、装配关系、SRC 开发回退和 Web 构建顺序见 [API Gateway](api-gateway.md)。
业务 Service 在 Host 使用 `@Remote``@RemoteContext` 声明可调用方法Host 构建生成 Host-for-Client 类型与运行时贡献Client 的 `api-remotes` 组合加载这些贡献并`ctx.remote` 与作用域 `agentCtx.remote` namespace。两侧的生成产物、装配关系、SRC 开发回退和 Web 构建顺序见 [API Gateway](api-gateway.md)。
如果相关的本地检查需要使用构建后的包产物,请先构建一次: