Table of Contents

Class MailAnsweringSpendTracker

Namespace
MailFathom.Infrastructure.Observability
Assembly
MailFathom.Infrastructure.dll

Holds what answering has cost in the period currently running, admits a question against it, and publishes both as instruments.

public sealed class MailAnsweringSpendTracker : IMailAnsweringSpendLedger
Inheritance
MailAnsweringSpendTracker
Implements
Inherited Members

Remarks

The period is the fixed window PeriodStartAt(DateTimeOffset) places, held as three numbers beside the start it currently counts under. The counts are dropped whenever a call notices that the clock has moved into a later window, rather than by a timer, so an idle deployment holds no callback and nothing here schedules work. Because the window is a function of the clock rather than of when the last reset happened, an instance that answered nothing for a day is not owed the windows that passed while it was idle.

Process-local, and this is where it diverges from IEmbeddingSpendLedger, which keeps its equivalent in a table so a crash-restart loop cannot begin every period again from zero. That reasoning applies here in kind and not in degree: an embedding sweep charges inside a transaction that was committing vectors anyway, while a question opens no write of its own, so making this durable would add a database write to the path of every provider call in every run. A restart therefore begins a new window with nothing spent, and an operator who needs the stronger guarantee needs the table rather than a longer period.

A refusal is counted as well as measured, because the two questions an operator asks are opposite: the counter says how often the ceiling was reached, and the gauges say how close the deployment is to reaching it now. A ceiling that is met constantly is a ceiling to raise or a client to look at, and neither is visible from a single number.

Only the first refusal of a period is written to the log, and that bound is the point rather than tidiness: a client that keeps asking is exactly what spends a period's allowance, so a line per refusal would put the log's volume on how enthusiastic that client is. The counter carries how often it happened; the line says that it started.

Nothing recorded here is mail or derived from it. The values are a run count and two token counts, and the one tag is an outcome from a closed set of two — which is a cardinality rule as much as a privacy one, since anything per caller or per question would open a time series that grows with use.

Constructors

MailAnsweringSpendTracker(MailAnsweringPeriodBounds, TimeProvider, ILogger<MailAnsweringSpendTracker>)

Initializes a ledger whose first period begins now, and the instruments it publishes through.

Methods

Read()

Reads what the current period has cost so far, rolling the window over first when the clock has left it.

RecordSpend(ChatTokenUsage)

Adds what one provider call consumed to the current period.

TryAdmitRun()

Takes an allowance for one run, if the current period has one left.