Skip to content

Refuse a span name declared in the enum and missing from the published set (#61) - #299

Merged
iderex merged 1 commit into
mainfrom
every-span-name-is-in-the-declared-set-61
Sep 4, 2026
Merged

Refuse a span name declared in the enum and missing from the published set (#61)#299
iderex merged 1 commit into
mainfrom
every-span-name-is-in-the-declared-set-61

Conversation

@iderex

@iderex iderex commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

The issue this belongs to

Belongs to #61. None of that issue's three conditions moves here, and the reason
is the one already on it: the first waits on the subsystems that own the six
sub-intervals, the second is met, and the third is met as far as 0061 states it
and open on a number #65 would produce.

What this is about is the thing that makes the first condition dangerous when it
does arrive.

What changed

SpanName::all is a second list beside the enum, and nothing kept the two
together. A case does now, reading the enum out of this file's own source and
comparing it against the set.

What failure it prevents

A span the core emits that the published set does not name, with nothing anywhere
going red.

0061 gives two reasons for declaring every name in one place, and the first is
#67: a set derivable by reading one file is a set a run can print rather than one
somebody keeps a list of.

git show origin/main:docs/decisions/0061-the-span-facility.md | sed -n '73,79p'
Every name is declared in one place in the tree rather than written as a literal
where it is emitted, for two reasons. #67 has to publish each measurement with
the command that produced it, and a set derivable by reading one file is a set a
run can print rather than one somebody keeps a list of. And 0008's argument
about naming the endpoints applies to the names themselves: a literal at an emit
site is renamed by whoever is working in that file, and a renamed span is a
number that stops arriving with nothing failing anywhere.

The compiler already refuses half of it. A variant with no arm in
SpanName::as_str does not compile. It has nothing to say about a variant
missing from SpanName::all, so the set goes short in silence, and a document
generated under #67 then names fewer spans than the build emits while reading as
complete. That is the same failure the record's last sentence describes, reached
from the other side.

It matters most exactly when this issue's first condition arrives. 0061 places
each sub-interval's identity with the issue that builds the subsystem emitting
it, so the six arrive one at a time from six different issues:

git show origin/main:src/measurement/mod.rs | sed -n '44,53p'
/// # What is here today, and what is not
///
/// The three intervals a build is gated on, from 0008. The six sub-intervals
/// that record names in prose - the cache read, the request, the wait for the
/// server, the parse, the artwork fetch and the artwork decode - are not here,
/// because 0061 places the identity of a sub-interval with the issue that builds
/// the subsystem emitting it, in the same way 0100 places the identity of a
/// diagnostic event. Adding one is a variant here and is not a change to any
/// record; renaming one of the three below is a change to 0008, because those
/// three are what a build is gated on and a rename detaches the gate from what it

Six people, six moments, six chances for the two lists to come apart by one. This
has not happened, because the enum has carried three variants since it landed and
both lists name all three. It is stated as what the shape allows rather than as an
incident.

The neighbouring register in this crate already carries the same disclosure and
has its own reading built for it, which is why this is the shape rather than an
invention:

git show origin/main:src/lifecycle/mod.rs | grep -n 'WHAT NOTHING HERE REFUSES IS A NAME DECLARED AND NOT LISTED' -A2
491:/// WHAT NOTHING HERE REFUSES IS A NAME DECLARED AND NOT LISTED. A field name is a
492:/// constant beside the event identity that carries it, which is where 0100 puts
493:/// it and where 0071 wants it, so a subsystem can declare one and emit it without

Evidence

The commit being pushed:

git rev-parse HEAD
71ab20eca95fd0c1e740f2100c858a3b936d83da

The two commands CONTRIBUTING.md names, run at it:

cargo build --locked --all-targets
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.12s

cargo test --locked
test result: ok. 587 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Four gate legs run by hand on this machine:

bash .github/format/format.sh check
Every tracked source file above is written the way the formatter would write it.

bash .github/lint/lint.sh check
Every lint the groups above carry was refused, outside the register printed with it.

bash .github/invariants/invariants.sh check
Every rule above was applied to its subject and refused nothing.

bash .github/doc-paths/doc-paths.sh check
Every path these documents name resolves against the tracked set.

What a guard here refuses, and the proof it bites

every_variant_of_the_enum_is_in_the_declared_set refuses a variant declared in
the enum and absent from SpanName::all. Every run below is
cargo test --locked --lib measurement, and the green run at the head is:

test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 573 filtered out

The violation is the change the seventh person makes, adding a sub-interval to
the enum and to as_str and forgetting the set, which is the only one of the
three the compiler does not ask for:

     /// What-to-play call entered to playable handover returned.
     PlayCore,
+    PlayCoreParse,
 }
             Self::PlayCore => "play.core",
+            Self::PlayCoreParse => "play.core.parse",
         }

test measurement::tests::every_variant_of_the_enum_is_in_the_declared_set ... FAILED
declared in the enum and absent from SpanName::all: ["PlayCoreParse"]
test result: FAILED. 13 passed; 1 failed; 0 ignored; 0 measured; 573 filtered out

The near miss, which is the same variant added to all three places, and which
has to stay green or the guard refuses the work it exists to protect:

     /// What-to-play call entered to playable handover returned.
     PlayCore,
+    PlayCoreParse,
 }
             Self::PlayCore,
+            Self::PlayCoreParse,
         ]
             Self::PlayCore => "play.core",
+            Self::PlayCoreParse => "play.core.parse",
         }

test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 573 filtered out

The case also carries a floor: a reading that finds fewer variants than the enum
has fails rather than passing quietly. A parser that stopped matching finds
nothing, reports no difference, and reads exactly like a set that is complete.
That the gate scripts in this tree refuse the same shape - an empty register, a
run that collected nothing, a scanner pointed at a moved file - is a claim, made
from CONTRIBUTING.md's descriptions of them rather than from a count of the
scripts.

What this does not cover

The reading is text. It finds the enum by its declaration and takes the
single-word capitalised lines inside it, so a variant written in a shape this
tree does not use - one carrying a payload, or one behind an attribute on its own
line - is not seen. The floor catches a reading that collapses to nothing and does
not catch one short by exactly the variant somebody added.

The other direction is not asked because the compiler already refuses it: a member
of SpanName::all names a variant, and a variant that does not exist does not
compile.

Nothing here says whether a name means what it says, which 0061 places outside
what any reading of this file makes.

None of #61's three conditions moves. No span is emitted by any subsystem, which
is the first, and nothing here adds a name to the set.

The equivalent gap in crate::lifecycle's field-name statement already has its
own reading in tests/the_rule_as_data_names_every_field.rs. Neither register is
changed here.

The coverage leg was not run on this machine, and src/measurement/ is not on the
pinned surface, which that register states as a deliberate exclusion rather than a
claim about coverage.

Who has read it

Nobody other than me. There was no second reader available, and the evidence above
stands in place of one.

…d set (#61)

0061 requires every span name to be declared in one place in the tree, and gives
#67 as one of its two reasons: a set derivable by reading one file is a set a run
can print rather than one somebody keeps a list of. `SpanName::all` is that set,
and it is a second list beside the enum.

The compiler refuses a variant missing an arm in `SpanName::as_str` and says
nothing about one missing from `SpanName::all`, so the failure that list can have
is silent: a span the core emits and the published set does not name, with nothing
anywhere going red. That is the shape declaring the names in one place exists to
prevent, arriving inside the place they are declared.

It matters most exactly when 0061 says the six sub-intervals arrive. Each is
placed with the issue that builds the subsystem emitting it, so six people add six
variants at six different times, and every one of them is a chance for the enum
and the set to come apart by one.

The case reads the enum out of this file's own source, embedded at compile time
because `std::fs` under `src/` is refused by the `no-filesystem-access` rule, and
compares it against `SpanName::all`. It carries a floor as well: a reading that
finds fewer variants than the enum has fails rather than passing quietly, because
a parser that stopped matching finds nothing and reads exactly like a set with no
difference in it.

Watched failing on a variant added to the enum and not to the set, and watched
staying green on the same variant added to both; PR #299 carries both runs.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit 3497314 into main Sep 4, 2026
27 checks passed
@iderex
iderex deleted the every-span-name-is-in-the-declared-set-61 branch September 4, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant