Runtime scoring
Tiaude exposes three scoring methods:
track() -> process one new event incrementally
scoreUser() -> rebuild from raw events
refreshScore() -> update time-sensitive scores without a new eventIf you remember one rule:
track()is the fast path.scoreUser()is the source-of-truth rebuild path.
track()
Use track() when a new event arrives.
const result = scorer.track({
userId: "user_123",
previousState: user.churnState ?? null,
event: {
name: "feature.used",
timestamp: "2026-05-20T10:00:00.000Z",
},
});Use it when:
- you are processing a new product event;
- you have the previous saved Tiaude state;
- events are processed in chronological order;
- you want the cheapest runtime update.
Rules:
previousStatemay benullfor the first event;- event timestamps must move forward;
now, when provided, must be greater than or equal to the event timestamp;- the state must belong to the same user;
- the state must be compatible with the current config.
track() returns a full ChurnResult.
Persist result.state after every successful call.
scoreUser()
Use scoreUser() when you need to rebuild from raw events.
const result = scorer.scoreUser({
userId: "user_123",
events: await loadUserEvents("user_123"),
now: new Date(),
});Use it when:
- bootstrapping an existing user;
- the saved state is missing;
- the saved state is invalid or corrupted;
- events arrived out of order;
- the scoring config changed;
- historical events were edited or deleted;
- you want to audit or debug a score.
Behavior:
- sorts events by timestamp;
- accepts an empty event history;
- rebuilds state from zero;
- returns the same result shape as
track().
scoreUser() is the safe fallback because it does not depend on previous compact state.
refreshScore()
Use refreshScore() when no new event arrived, but time has passed.
const result = scorer.refreshScore({
userId: "user_123",
previousState: user.churnState,
now: new Date(),
});Use it for:
- scheduled jobs;
- account health dashboards;
- CRM sync;
- proactive churn review workflows.
Behavior:
- consumes no new event;
- ages time-sensitive signals;
- preserves event counters;
- updates
computedAt; - recalculates score, confidence, freshness, reasons, and actions.
Important:
refreshScore() does not make stale data fresh.
Freshness is based on the latest relevant event, not only on the refresh time.
Decision model
if (newEventArrived) {
return scorer.track({
userId,
previousState,
event,
});
}
if (mustRebuildFromHistory) {
return scorer.scoreUser({
userId,
events,
});
}
return scorer.refreshScore({
userId,
previousState,
now: new Date(),
});Timeline rule
Incremental state can move forward only.
If a state was computed at a future time, Tiaude will reject attempts to reuse it at an earlier time.
For historical debugging, use:
scorer.scoreUser({
userId,
events,
now: "2026-05-01T00:00:00.000Z",
});Do not use an already-advanced previousState to go backward in time.
Storage rule
To get the benefits of track(), store:
- raw events in your database;
- latest Tiaude state per user.
Without saved state, you lose the incremental path.
Without raw events, you lose the safe rebuild path.