Skip to content

Add an ergonomic 'patterns at a moment' query over the facet-set API #57

Description

@einari

The .NET client gained an ergonomic wrapper over the low-level pattern query, and the other clients should offer the same capability in their own idiom.

What it is

Behavior patterns are queried with a facet set — a partial context of Day, TimeBucket, CommandType, AggregateType and so on. That is the right primitive, but it is not the question an application actually has. The question is what does this person normally do at this point in the week?

So on top of it:

// Right now
var patterns = await eventStore.Patterns.GetPatternsAt(userId);

// A given moment
var patterns = await eventStore.Patterns.GetPatternsAt(userId, tomorrowMorning);

// Narrower than a moment
var patterns = await eventStore.Patterns.GetPatternsAt(
    userId,
    alsoConstraining: FacetSet.Empty.With(FacetName.AggregateType, "Invoice"));

The contract, which every client should keep:

  • Scope is required — normally the user.
  • The moment is optional and defaults to now. That default is the whole point; the common call is one argument.
  • Day and TimeBucket are derived from the moment, and the caller never passes them.
  • Further facets can be added, so asking about a moment and asking about a command are the same call rather than two competing ones.
  • The low-level facet-set query stays — this is a wrapper, not a replacement.

The part that actually matters

The time bucket must be derived with the same rule the engine mined with. In .NET that rule now lives on the concept (DateTimeOffset.ToTimeBucket()) rather than inside the kernel, precisely so the client and the engine share one copy of it, and the client exposes it so applications never write their own.

Get this wrong and nothing fails loudly. The query asks about a slot the mining never used and comes back empty, which is indistinguishable from "this person has no established behavior" — the one answer the API is supposed to be trustworthy about.

The buckets, from the event's own offset rather than UTC (somebody who works at nine does so at nine in their morning):

Hours Bucket
05:00–08:00 EarlyMorning
08:00–11:00 Morning
11:00–14:00 Midday
14:00–17:00 Afternoon
17:00–22:00 Evening
22:00–05:00 Night

Day is the day of week of the moment, again read from its own offset.

References

  • Reference documentation: Documentation/patterns/index.md in Cratis/Chronicle, section "Asking about a moment" — the client-neutral contract, with a table each client adds a row to.
  • .NET implementation: Source/Clients/DotNET/Patterns/Patterns.cs and IPatterns.cs.
  • Shared rule: Source/Kernel/Concepts/Patterns/TimeBucketExtensions.cs.
  • No gRPC contract change is involved — this builds the facet set client-side and calls the existing GetPatterns.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions