feat(goal): add persisted same-session goal domain
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# Same-session goals
|
||||
|
||||
Types shared by the event-sourced goal domain and its policy consumers. The [goal-domain RFC](../rfc/implemented/feature/2026-07-19-persisted-same-session-goal-domain.md) owns the persistence and activation decisions; this page records the literal shapes from [`packages/goal/goal/src/types.ts`](../../packages/goal/goal/src/types.ts).
|
||||
|
||||
## Identity and lifecycle
|
||||
|
||||
`GoalId` is a [branded id](core.md#branded-ids). A caller mutates one exact revision through `GoalRef`; every accepted durable mutation increments the revision.
|
||||
|
||||
```ts type-equiv
|
||||
/** Compare-and-set identity for one exact goal revision. */
|
||||
interface GoalRef {
|
||||
/** Stable goal identity. */
|
||||
readonly id: GoalId
|
||||
/** Positive revision; every durable mutation increments it. */
|
||||
readonly revision: number
|
||||
}
|
||||
```
|
||||
|
||||
The durable phase answers what happened to the objective. Process-local activation separately answers whether a continuation consumer may start another round.
|
||||
|
||||
```ts type-equiv
|
||||
/** Durable continuation phase. Activation is process-local and separate. */
|
||||
type GoalPhase =
|
||||
| 'active'
|
||||
| 'paused'
|
||||
| 'blocked'
|
||||
| 'usage-limited'
|
||||
| 'budget-limited'
|
||||
| 'complete'
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Full durable state written by every non-clear goal mutation. */
|
||||
interface GoalSnapshot extends GoalRef {
|
||||
/** Human-requested completion objective. */
|
||||
readonly objective: string
|
||||
/** Durable lifecycle phase. */
|
||||
readonly phase: GoalPhase
|
||||
/** Total admitted goal-round cap. */
|
||||
readonly maxGoalRounds: number
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Current goal projection, including values derived from the session log. */
|
||||
interface GoalView extends GoalSnapshot {
|
||||
/** Highest admitted round number for this goal. */
|
||||
readonly roundsStarted: number
|
||||
/** Epoch milliseconds of the create mutation. */
|
||||
readonly createdAt: number
|
||||
/** Epoch milliseconds of the latest mutation. */
|
||||
readonly updatedAt: number
|
||||
/** Process-local continuation eligibility; never persisted. */
|
||||
readonly activation: GoalActivation
|
||||
}
|
||||
```
|
||||
|
||||
## Durable changes
|
||||
|
||||
Every mutation is a `context/message` whose metadata is either a complete snapshot or a clear tombstone. The version, metadata, goal source, raw envelope, and rendered content form one replay invariant.
|
||||
|
||||
```ts type-equiv
|
||||
/** Full-snapshot goal mutation retained in a model-visible context event. */
|
||||
interface GoalSnapshotChangeMeta {
|
||||
readonly kind: 'goal/change'
|
||||
readonly version: 1
|
||||
readonly operation: Exclude<GoalOperation, 'clear'>
|
||||
readonly goal: GoalSnapshot
|
||||
readonly roundsStarted: number
|
||||
readonly createdAt: number
|
||||
readonly updatedAt: number
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Tombstone retained when the current goal is cleared. */
|
||||
interface GoalClearChangeMeta {
|
||||
readonly kind: 'goal/change'
|
||||
readonly version: 1
|
||||
readonly operation: 'clear'
|
||||
readonly cleared: GoalRef
|
||||
readonly clearedAt: number
|
||||
}
|
||||
```
|
||||
|
||||
Goal state changes use round `0`. A continuation consumer attributes each admitted user-message turn with a positive, sequential round number and the current revision; replay rejects gaps, stale revisions, stopped phases, and cap overflow.
|
||||
|
||||
```ts type-equiv
|
||||
/** Message attribution for durable goal state and continuation rounds. */
|
||||
interface GoalMessageSource {
|
||||
readonly kind: 'goal'
|
||||
readonly goalId: GoalId
|
||||
readonly revision: number
|
||||
/** Zero for state changes; positive for admitted continuation rounds. */
|
||||
readonly round: number
|
||||
}
|
||||
```
|
||||
|
||||
## Requests and notifications
|
||||
|
||||
Creation separates caller omission from the resolved deployment choice. An edit is a partial replacement whose runtime validator requires at least one field. Every mutation notification carries the accepted operation and exact revision; clear omits `goal`.
|
||||
|
||||
```ts type-equiv
|
||||
/** Input whose omitted round cap is resolved by the service configuration. */
|
||||
interface CreateGoalRequest {
|
||||
readonly objective: string
|
||||
readonly maxGoalRounds?: number
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Validated create input with every deployment default materialized. */
|
||||
interface CreateGoalSpec {
|
||||
readonly objective: string
|
||||
readonly maxGoalRounds: number
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Fields changed by an edit; at least one must be present. */
|
||||
interface EditGoalRequest {
|
||||
readonly objective?: string
|
||||
readonly maxGoalRounds?: number
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/** Live notification after one goal mutation has been accepted for logging. */
|
||||
interface GoalChanged {
|
||||
readonly operation: GoalOperation
|
||||
readonly ref: GoalRef
|
||||
/** Absent for a clear tombstone. */
|
||||
readonly goal?: GoalView
|
||||
}
|
||||
```
|
||||
|
||||
## Service behavior
|
||||
|
||||
[`GoalService`](../../packages/goal/goal/src/index.ts) resolves creation defaults, folds strict replay, enforces exact-live-agent identity and compare-and-set mutations, overlays deferred injections, and emits contained `goal/changed` notifications. The package [README](../../packages/goal/goal/README.md) owns the callable and model-visible contract.
|
||||
Reference in New Issue
Block a user