feat(web): re-land the goals wire domain as mutation-only ref acknowledgements
Six mutation RPCs (create/edit/pause/resume/complete/clear) move into
dsh-host-apiproxy (the PR's host/runtime carrier is gone): goalService()
resolves ctx.get('goals') with a loud absence error, mutateGoal() resolves
the session's agent (agentFor, the command.* implicit-resume precedent) and
acknowledges with the new CAS ref only. GoalError codes ride err.details.
goal.get and the wire GoalView/goalViewSchema are gone: the read side is the
'goal' session projection (whole values on the history tail page and
session/projection frames), so responses never feed client state — the rule
whose absence forced the original PR's write-revision fences.
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
/**
|
||||
* goals domain contract. Method signatures are the source of truth:
|
||||
* unary methods take the RpcRequest<P> narrow form and the impl echoes rpcId.
|
||||
*
|
||||
* Mutations only: the read side is the 'goal' session projection (history
|
||||
* tail-page projections block + session/projection frames), so there is no
|
||||
* goal.get and no wire goal view — responses acknowledge with the new CAS
|
||||
* ref and never feed client state (the committed goal/change event reaches
|
||||
* every client through the mux stream carrying the same whole value).
|
||||
*/
|
||||
|
||||
import type { Branded } from '@deepseek-ai/dsh-brand'
|
||||
@@ -16,69 +22,27 @@ export interface GoalRef {
|
||||
readonly revision: number
|
||||
}
|
||||
|
||||
/** Durable continuation phase. */
|
||||
export type GoalPhase =
|
||||
| 'active'
|
||||
| 'paused'
|
||||
| 'blocked'
|
||||
| 'complete'
|
||||
|
||||
/** Machine-routable and human-readable explanation for a blocked goal. */
|
||||
export interface GoalBlockReason {
|
||||
readonly code: string
|
||||
readonly message: string
|
||||
}
|
||||
|
||||
/** Whether this live process may automatically continue an active goal. */
|
||||
export type GoalActivation = 'armed' | 'disarmed'
|
||||
|
||||
/** Current goal projection, including values derived from the session log. */
|
||||
export interface GoalView {
|
||||
readonly id: GoalId
|
||||
readonly revision: number
|
||||
readonly objective: string
|
||||
readonly phase: GoalPhase
|
||||
readonly blockedReason?: GoalBlockReason
|
||||
readonly maxGoalRounds: number
|
||||
readonly roundsStarted: number
|
||||
readonly createdAt: number
|
||||
readonly updatedAt: number
|
||||
readonly activation: GoalActivation
|
||||
}
|
||||
|
||||
/** Input whose omitted round cap is resolved by the service configuration. */
|
||||
export interface CreateGoalRequest {
|
||||
readonly objective: string
|
||||
readonly maxGoalRounds?: number
|
||||
}
|
||||
|
||||
/** Fields changed by an edit; at least one must be present. */
|
||||
export interface EditGoalRequest {
|
||||
readonly objective?: string
|
||||
readonly maxGoalRounds?: number
|
||||
}
|
||||
|
||||
/** Goal-domain unary methods (mutations only: the read side is the 'goal' session projection). */
|
||||
/** Goal-domain unary methods (every mutation resolves the session's agent and applies one CAS-guarded verb). */
|
||||
export interface GoalsApi {
|
||||
/** Create and arm a goal. */
|
||||
create(request: RpcRequest<{ sessionId: SessionId; objective: string; maxGoalRounds?: number }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
Promise<RpcResponse<{ ref: GoalRef }>>
|
||||
|
||||
/** Edit objective and/or round cap without changing phase. */
|
||||
edit(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef; objective?: string; maxGoalRounds?: number }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
Promise<RpcResponse<{ ref: GoalRef }>>
|
||||
|
||||
/** Pause an active goal and disarm automatic continuation. */
|
||||
pause(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
Promise<RpcResponse<{ ref: GoalRef }>>
|
||||
|
||||
/** Resume and arm a stopped goal. */
|
||||
resume(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
Promise<RpcResponse<{ ref: GoalRef }>>
|
||||
|
||||
/** Mark a current non-complete goal complete and disarm it. */
|
||||
complete(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>):
|
||||
Promise<RpcResponse<{ goal: GoalView }>>
|
||||
Promise<RpcResponse<{ ref: GoalRef }>>
|
||||
|
||||
/** Clear the current goal while retaining a durable tombstone and history. */
|
||||
clear(request: RpcRequest<{ sessionId: SessionId; ref: GoalRef }>):
|
||||
|
||||
Reference in New Issue
Block a user