Documentation · Labels

What makes a good labeling schema

Labels are Moment Tally's whole query model — reports, export filters, and the source-control join are only as good as the schema behind them. These principles come from running Prometheus metrics at scale, where label schemas succeed and collapse for exactly the same reasons.

Labels are the query model

There is no folder tree in Moment Tally — a span is its labels. Every question you'll ever ask of your history ("hours per client this quarter", "review share by repo", "which spans map to that shipped PR?") is a group-by or a filter over label keys. That makes the schema — which keys exist, what values they take — the highest-leverage decision you make. Good news: a good schema is small, and the rules fit on one page.

Six principles

01

Label what you'll query by

A label earns its place by being grouped or filtered on. If you'd never break a report down by it or filter an export on it, it isn't a label — it's a note. Moment Tally has notes; use them for the color, and keep labels for the axes.

02

Cardinality is the budget

Every distinct value a key takes is one more bucket in every report that groups by it. Values should come from a small, slowly growing vocabulary. Unbounded values — ticket titles, timestamps, one-off prose — degenerate grouping into one span per bucket, and your reports stop compressing anything.

03

One fact per key

Don't pack repo, feature, and kind of work into a single value. Three separate keys filter and join independently; a compound value can only ever be matched whole, and you'll be splitting strings in a spreadsheet within a month.

04

Few, stable keys, consistently named

Pick repo once — not proj on Mondays and project on Thursdays. Renaming a key later severs your history in every query that uses it. Label Review can rescue a drifted schema, but a schema that never drifts needs no rescue.

05

Mirror the system you'll join against

If you plan to line time up with source control, use your code host's exact naming: repo: sfi/moment-tally, not repo: momenttally. Joins are literal — a value that's merely close matches nothing.

06

Decide what unlabeled means

Absent is a value too. Decide what a span with no client — or no repo — means in your reports (internal? overhead? unbilled?) and apply it consistently, so the gaps in your data carry information instead of doubt.

A starter schema

Four keys cover most solo and small-team work. Each holds one fact, each value comes from a vocabulary you could list from memory, and repo uses your code host's exact naming so exports join cleanly against commits and PRs.

labels
# four keys, each drawing from a small, stable vocabulary
repo:    sfi/moment-tally   # exact source-control path — joins against commits & PRs
feat:    label-review       # the feature or stream of work
type:    review             # build | review | support | ops
client:  acme               # who the hours belong to
repo: sfi/moment-tally feat: label-review type: review client: acme one span · four axes

What this buys you: hours per client across every repo, type: review share per repo, and a span-to-PR join for the time-joined-to-what-shipped workflow — none of which required deciding a hierarchy up front. Start smaller if in doubt; a key is easy to add and painful to rename.

How schemas fail

The same schema, gone wrong — each of these looks harmless on the day you type it, and each quietly breaks a query you'll want later.

task: fix-flaky-ci-on-auth-service-again

Unbounded values

Every span invents a new value, so grouping by task yields one span per bucket — the report is just your log, re-sorted. This is a note wearing a label costume.

work: moment-tally-auth-bugfix

Three facts fused into one key

Repo, area, and type are welded together, so you can never ask "all bugfix time, across repos" without string surgery. Split it: repo, area, type.

proj: momenttally · project: moment-tally

Drifting key names and spellings

Half your history lands under each spelling. Every query needs an OR, and totals silently miss whichever variant you forget.

repo: momenttally

Approximate naming

Your code host calls it sfi/moment-tally. A close-but-not-exact value matches nothing when you join time to commits and PRs — the whole point of the key.

Already drifted? Label Review can merge variant keys and retire noisy values after the fact — your history is editable, not carved in stone. But every rescue is a query you couldn't run in the meantime.

The Prometheus lineage

None of this guidance is original, and that's its strength. Moment Tally's label system is modeled on Prometheus metric labels, and these principles are the operational lessons of running Prometheus at scale: high-cardinality labels explode timeseries the way they drown reports; compound values resist aggregation; renaming a label severs history. Time tracking hits the same walls for the same reasons — so we wrote down the same rules. More on what Moment Tally borrows, and from whom, on the attributions page.