Skip to content
C.W.K.
Stream
Lesson 04 of 05 · published

Too Young for a Percentile

~13 min · reference-scale, bootstrapping, auditability, flags

Level 0Raw Ore
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
Every series starts with no history. The design question is what you show on day one, and how you label it.

The bootstrapping problem

A percentile requires history. A newly shipped gauge has none. This is not an edge case to be handled defensively — every series in the product passes through it, and two of the most prominent ones were in exactly that state while this quest was being written: the composite, and the concentration measure, both begun days earlier, both reporting a percentile of None over a window of zero years.

So what does the card show? Three answers, in ascending order of honesty.

Show nothing. Defensible, and it means a genuinely useful new measurement is invisible for months until its history matures. That is a real cost, paid entirely by the reader.

Show a percentile computed over the three points you have. Never do this — and note that the floor in this codebase is twenty, so three is not a near miss. It renders identically to a percentile over a century and there is no visual signal distinguishing them. This is the option that quietly destroys the reader's ability to calibrate anything on the page.

Score it against a documented reference range, and mark it as such. The number is now a position within a range somebody chose and wrote down, rather than a position within observed history — a weaker claim, honestly labelled.

The flag that is not decoration

The scoring function takes one of two paths and reports which: own-history percentile when the series has earned one, the documented reference scale until then, flagged. The docstring says exactly why the flag exists — a reference score is a claim about an assumed range, and it must never be mistaken for a measured one.

That sentence is doing real work. Without the flag the two paths produce the same shape of output, and downstream nobody can tell which they received. With it, a surface can render them differently, a brief can quote the distinction, and — critically — the composite can report which of its members were reference-scored rather than measured.

When a value can arrive by two paths of different strength, the path is part of the value. Estimated versus measured, cached versus fresh, defaulted versus supplied, inferred versus stated. Any time your code has an if-else that produces the same type on both branches, ask whether the consumer needs to know which branch ran. Usually they do, and usually nobody told them.

Why the scales are numbers rather than functions

The reference scales are plain linear maps: a low value that scores zero, a high value that scores one hundred. The comment explaining why is one of the sharpest lines in the codebase — a lambda cannot be stored, served, or audited.

Consider what a small scoring function costs you. It cannot be written to a database. It cannot be returned by an API. It cannot be quoted in a delegation brief, diffed meaningfully in review, or checked by anyone who does not read the source. A pair of numbers can do all of those. And since every scale the dashboard already used happened to be linear, expressing them as data cost precisely nothing.

The general form: prefer a declarative representation over a procedural one whenever the procedure is not actually using its extra power. Code is more expressive than data, and that expressiveness is exactly what makes it opaque to every tool that is not an interpreter.

Code

Two paths to a score, and the flag that keeps them distinguishable·python
# Reference scales as DATA -- lo scores 0, hi scores 100.
# Every scale the dashboard used was already linear, so a pair of
# numbers loses nothing, and a lambda cannot be stored, served,
# or audited.
{"key": "cape",   "ref": {"lo": 0.0, "hi": 44.2}}
{"key": "vix",    "ref": {"lo": 40.0, "hi": 8.0}}   # inverted: hi < lo
{"key": "hy_oas", "ref": {"lo": 6.0, "hi": 1.5}}   # tight spread = rich


def score_indicator(spec, row) -> dict[str, Any]:
    """One indicator's 0-10 score, and WHICH PATH produced it.

    Own-history percentile when the series has earned one; the
    card's documented reference scale until then, flagged
    `reference: True`. The flag is not decoration -- a reference
    score is a claim about an assumed range, and it must never be
    mistaken for a measured one."""
    if row["percentile"] is not None:
        pct = (100.0 - row["percentile"]) if spec["invert"] \
            else row["percentile"]
        reference = False
    else:
        pct = _reference_score(row["value"], spec["ref"])
        reference = True
    return {
        "key": spec["key"], "name": spec["name"],
        "category": spec["category"], "value": row["value"],
        "data_date": row["data_date"],
        "percentile": row["percentile"], "points": row["points"],
        "window_years": row["window_years"],
        "score": round(round(pct) / 10.0, 2),
        "reference": reference,
    }

External links

Exercise

Find a place in your code where a fallback produces the same output type as the primary path — a default value, a cached result, an estimate. Check whether any consumer can tell which one it got. If not, add the flag and then look at how consumers respond: the ones that start branching on it were making a silent assumption you have just made visible.
Hint
The highest-value version of this is anything that distinguishes measured from assumed. Systems accumulate assumptions that were reasonable when introduced and become invisible once they render the same as measurements — and nobody revisits an assumption they cannot see.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.