store: give ecosystem traces their own table
Traces were written as facts. A single Praxis action wrote several of them, so machine-rate rows crowded out the bounded fact readers that humans and evaluation consume. The habit profile window of 2000 facts and the memeval snapshot both filled with call records instead of what Maven learned about the owner. Traces now go to ecosystem_traces, with correlation, causation, duration and HTTP status as columns, pruned to the most recent 5000. The new reader is exposed over IPC and rendered as the Calls card on the ecosystem page, so it is a table someone actually looks at. Found in review of #84.
This commit is contained in:
@@ -24,6 +24,23 @@ type Fact struct {
|
||||
VoidsID *int64 `json:"voids_id,omitempty"`
|
||||
}
|
||||
|
||||
// EcosystemTrace — one hop of a cross-service ecosystem call, read by the
|
||||
// monitoring surfaces. Traces live in their own store table, not in facts:
|
||||
// they are written at machine rate and would otherwise crowd every bounded
|
||||
// reader of facts.
|
||||
type EcosystemTrace struct {
|
||||
ID int64 `json:"id"`
|
||||
Ts time.Time `json:"ts"`
|
||||
Service string `json:"service"`
|
||||
Operation string `json:"operation"`
|
||||
Status string `json:"status"`
|
||||
DurationMs int64 `json:"duration_ms"`
|
||||
CorrelationID string `json:"correlation_id"`
|
||||
CausationID string `json:"causation_id"`
|
||||
HTTPStatus int `json:"http_status"`
|
||||
Fields map[string]any `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// Bucket — presence hysteresis state: "present" | "away".
|
||||
type Bucket string
|
||||
|
||||
@@ -588,6 +605,10 @@ type CoreAPI interface {
|
||||
RecentFacts(ctx context.Context, n int) ([]Fact, error)
|
||||
CalendarEvents(ctx context.Context, from, to time.Time) ([]Fact, error)
|
||||
RecentNudges(ctx context.Context, n int) ([]Nudge, 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)
|
||||
WriteNote(ctx context.Context, ts time.Time, text string, embedding []float32, source string) (int64, error)
|
||||
QueryNotes(ctx context.Context, embedding []float32, k int) ([]Note, error)
|
||||
RecentNotes(ctx context.Context, n int) ([]Note, error)
|
||||
|
||||
@@ -64,6 +64,7 @@ var readOnlyMethods = map[Method]bool{
|
||||
MethodRecentFacts: true,
|
||||
MethodCalendarEvents: true,
|
||||
MethodRecentNudges: true,
|
||||
MethodRecentEcoTraces: true,
|
||||
MethodQueryNotes: true,
|
||||
MethodRecentNotes: true,
|
||||
MethodLookupTool: true,
|
||||
@@ -342,6 +343,14 @@ func (c *Client) CalendarEvents(ctx context.Context, from, to time.Time) ([]Fact
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecentEcosystemTraces(ctx context.Context, n int) ([]EcosystemTrace, error) {
|
||||
var out []EcosystemTrace
|
||||
if err := c.call(ctx, MethodRecentEcoTraces, nReq{N: n}, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *Client) RecentNudges(ctx context.Context, n int) ([]Nudge, error) {
|
||||
var out []Nudge
|
||||
if err := c.call(ctx, MethodRecentNudges, nReq{N: n}, &out); err != nil {
|
||||
|
||||
@@ -132,6 +132,22 @@ func (a *storeAPI) CalendarEvents(ctx context.Context, from, to time.Time) ([]Fa
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a *storeAPI) RecentEcosystemTraces(ctx context.Context, n int) ([]EcosystemTrace, error) {
|
||||
trs, err := a.s.RecentEcosystemTraces(ctx, n)
|
||||
if err != nil {
|
||||
return nil, mapErr(err)
|
||||
}
|
||||
out := make([]EcosystemTrace, len(trs))
|
||||
for i, tr := range trs {
|
||||
out[i] = EcosystemTrace{
|
||||
ID: tr.ID, Ts: tr.Ts, Service: tr.Service, Operation: tr.Operation,
|
||||
Status: tr.Status, DurationMs: tr.DurationMs, CorrelationID: tr.CorrelationID,
|
||||
CausationID: tr.CausationID, HTTPStatus: tr.HTTPStatus, Fields: tr.Fields,
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a *storeAPI) RecentNudges(ctx context.Context, n int) ([]Nudge, error) {
|
||||
ns, err := a.s.RecentNudges(ctx, n)
|
||||
if err != nil {
|
||||
@@ -774,6 +790,16 @@ var methodTable = map[Method]handlerFunc{
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodRecentEcoTraces: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]EcosystemTrace, error) {
|
||||
out, err := api.RecentEcosystemTraces(ctx, p.N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if out == nil {
|
||||
out = []EcosystemTrace{}
|
||||
}
|
||||
return out, nil
|
||||
}),
|
||||
MethodRecentNudges: withParams(func(ctx context.Context, api CoreAPI, p nReq) ([]Nudge, error) {
|
||||
out, err := api.RecentNudges(ctx, p.N)
|
||||
if err != nil {
|
||||
|
||||
@@ -68,6 +68,9 @@ func (UnimplementedCoreAPI) CalendarEvents(ctx context.Context, from, to time.Ti
|
||||
func (UnimplementedCoreAPI) RecentNudges(ctx context.Context, n int) ([]Nudge, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
func (UnimplementedCoreAPI) RecentEcosystemTraces(ctx context.Context, n int) ([]EcosystemTrace, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
func (UnimplementedCoreAPI) WriteNote(ctx context.Context, ts time.Time, text string, embedding []float32, source string) (int64, error) {
|
||||
return 0, ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ const (
|
||||
MethodRecentFacts Method = "recent_facts"
|
||||
MethodCalendarEvents Method = "calendar_events"
|
||||
MethodRecentNudges Method = "recent_nudges"
|
||||
MethodRecentEcoTraces Method = "recent_ecosystem_traces"
|
||||
MethodWriteNote Method = "write_note"
|
||||
MethodQueryNotes Method = "query_notes"
|
||||
MethodRecentNotes Method = "recent_notes"
|
||||
|
||||
Reference in New Issue
Block a user