the ring reads out over ipc as turn decisions (V-564)
Same shape as TickTrace and RecentEvents: a bounded daemon ring, so the store adapter refuses rather than pretending a table exists. No voice wiring means an empty list and not an error, because a box with no voice path has had no turns to arbitrate.
This commit is contained in:
@@ -836,6 +836,30 @@ type TickTrace struct {
|
||||
Rules []RuleTrace `json:"rules"`
|
||||
}
|
||||
|
||||
// --- Turn decision trace DTOs (V-564) ---
|
||||
|
||||
// TurnClaim — one claimant's say on one turn: who, at which stage, what it
|
||||
// would have made the turn, the score it reported if it has one, and what
|
||||
// happened to the claim. Same shape as RuleTrace above and for the same reason:
|
||||
// a winner alone does not explain an arbitration, the losers do.
|
||||
type TurnClaim struct {
|
||||
Stage string `json:"stage"`
|
||||
Claimant string `json:"claimant"`
|
||||
Intent string `json:"intent,omitempty"`
|
||||
Score float64 `json:"score,omitempty"`
|
||||
HasScore bool `json:"has_score,omitempty"`
|
||||
Outcome string `json:"outcome"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// TurnDecision — one turn's arbitration, newest first when read as a list.
|
||||
type TurnDecision struct {
|
||||
Ts time.Time `json:"ts"`
|
||||
Utterance string `json:"utterance"`
|
||||
Winner string `json:"winner"`
|
||||
Claims []TurnClaim `json:"claims"`
|
||||
}
|
||||
|
||||
// MorningRoutineItem — one checklist entry's current state.
|
||||
type MorningRoutineItem struct {
|
||||
Key string `json:"key"`
|
||||
|
||||
@@ -672,6 +672,14 @@ func (c *Client) TickTrace(ctx context.Context) (TickTrace, error) {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (c *Client) TurnDecisions(ctx context.Context, n int) ([]TurnDecision, error) {
|
||||
var d []TurnDecision
|
||||
if err := c.call(ctx, MethodTurnDecisions, nReq{N: n}, &d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecentEvents(ctx context.Context, n int) ([]IntakeEvent, error) {
|
||||
var e []IntakeEvent
|
||||
if err := c.call(ctx, MethodRecentEvents, nReq{N: n}, &e); err != nil {
|
||||
|
||||
@@ -169,6 +169,13 @@ type SystemAPI interface {
|
||||
// persisted — it's a daemon-level cache).
|
||||
TickTrace(ctx context.Context) (TickTrace, error)
|
||||
|
||||
// TurnDecisions returns the newest turn arbitration records, newest first
|
||||
// (V-564). Same shape as TickTrace and RecentEvents: a bounded in-memory
|
||||
// ring on the daemon, so the store adapter returns an error rather than
|
||||
// pretending a table exists. Empty is a normal answer — it means no turn
|
||||
// has run since the daemon started.
|
||||
TurnDecisions(ctx context.Context, n int) ([]TurnDecision, error)
|
||||
|
||||
// RecentEcosystemTraces reads the ecosystem call log, which lives in its
|
||||
// own table so machine-rate traces never crowd out human-rate facts.
|
||||
RecentEcosystemTraces(ctx context.Context, n int) ([]EcosystemTrace, error)
|
||||
|
||||
@@ -583,6 +583,13 @@ var methodTable = map[Method]handlerFunc{
|
||||
MethodTickTrace: withoutParams(func(ctx context.Context, api CoreAPI) (TickTrace, error) {
|
||||
return api.TickTrace(ctx)
|
||||
}),
|
||||
MethodTurnDecisions: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]TurnDecision, error) {
|
||||
d, err := api.TurnDecisions(ctx, p.N)
|
||||
if d == nil {
|
||||
d = []TurnDecision{}
|
||||
}
|
||||
return d, err
|
||||
}),
|
||||
// MorningStatus intentionally has no nil→[]T{} normalization here — the
|
||||
// pre-table arm marshaled api.MorningStatus's result as-is (a nil slice
|
||||
// serializes as JSON null), and this preserves that exact wire shape.
|
||||
|
||||
@@ -265,6 +265,12 @@ func (a *storeAPI) TickTrace(ctx context.Context) (TickTrace, error) {
|
||||
return TickTrace{}, errors.New("store: tick trace not available via direct store API")
|
||||
}
|
||||
|
||||
// TurnDecisions — same story as TickTrace: the arbitration record is a daemon
|
||||
// ring, not a table, so there is nothing here to read it from (V-564).
|
||||
func (a *storeAPI) TurnDecisions(ctx context.Context, n int) ([]TurnDecision, error) {
|
||||
return nil, errors.New("store: turn decisions not available via direct store API")
|
||||
}
|
||||
|
||||
// SeedEvent — same shape as MorningStatus: writing the fact is a store call,
|
||||
// but extraction and detect-and-propose live in mavend, and a seed that wrote
|
||||
// the fact without running them would be the one thing this seam must not be,
|
||||
|
||||
@@ -144,6 +144,9 @@ func (UnimplementedCoreAPI) RevertFact(ctx context.Context, key string) (int64,
|
||||
func (UnimplementedCoreAPI) TickTrace(ctx context.Context) (TickTrace, error) {
|
||||
return TickTrace{}, ErrNotImplemented
|
||||
}
|
||||
func (UnimplementedCoreAPI) TurnDecisions(ctx context.Context, n int) ([]TurnDecision, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
func (UnimplementedCoreAPI) MorningStatus(ctx context.Context) ([]MorningRoutineStatus, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ const (
|
||||
MethodAcceptProposedRoutine Method = "accept_proposed_routine"
|
||||
MethodRevertFact Method = "revert_fact"
|
||||
MethodTickTrace Method = "tick_trace"
|
||||
MethodTurnDecisions Method = "turn_decisions"
|
||||
MethodMorningStatus Method = "morning_status"
|
||||
MethodMCPServers Method = "mcp_servers"
|
||||
MethodDayPlan Method = "day_plan"
|
||||
|
||||
Reference in New Issue
Block a user