Skip to content

Hold 0071's rule as data, and check that the statement is not short (#71) - #289

Merged
iderex merged 1 commit into
mainfrom
the-rule-as-data-every-field-name-carries-71
Sep 2, 2026
Merged

Hold 0071's rule as data, and check that the statement is not short (#71)#289
iderex merged 1 commit into
mainfrom
the-rule-as-data-every-field-name-carries-71

Conversation

@iderex

@iderex iderex commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

The issue this belongs to

Refs #71. It reaches the third of that issue's conditions in the form 0071
substitutes for it, and neither of the other two, so no closing keyword is
written here: four landings on this board have written "does not close #N" and
GitHub read the keyword out of the sentence with the negation discarded.

What changed

#71's third condition is that the bundle names its own exclusions, and
docs/decisions/0071-what-may-leave-through-a-diagnostic-event.md answers it by
refusing the bundle. 0068 and 0100 both fix that an event is handed over and
forgotten in the same call, with no ring buffer and nothing retained, so there is
no store of past events for the core to assemble one out of. What that record
asks the core for instead is the rule as data: for each field name it has ever
emitted, which of the three treatments it applies. A client assembling a bundle
out of what its own sink kept includes the statement verbatim, so whoever is
about to send it can read what is not in it. Nothing in the tree produced it.

lifecycle::every_field_name_the_core_emits is that statement. It is gathered
there rather than in src/diagnostics/ because 0071 deliberately keeps a field
name beside the event identity that carries it, which is 0100's placement, so the
only place that sees all of them is the place that sees every subsystem, and
0115 makes that creation. The nine names the two cache modules declare become
visible to the crate and to nothing outside it.

What failure it prevents

The one way the statement can be wrong in the direction that matters is by being
SHORT. A subsystem declares a name beside its event and emits it, the gathered
list does not move, and the statement is then incomplete while it goes on reading
as complete. A bundle carrying it tells somebody a value is not in their events
when it is, which is worse than saying nothing, and it is exactly the shape 0071
exists against.

Nothing inside the crate can catch that. The list and the declarations are the
same kind of thing to the compiler, and a missing entry is a shorter array rather
than an error.

tests/the_rule_as_data_names_every_field.rs catches it. Its subject is the
source read as bytes, which is why it is a test target rather than a case in the
module: no-filesystem-access in .github/invariants/rules refuses std::fs
under src/, grounded in 0003, and reading the tree is exactly what this has to
do. It compares what the tree declares against the statement in both directions,
and it checks that the treatment stated for a name is the one its declaration
gave it, which is 0071's own reversal condition rather than a worry invented
here.

Evidence

Read at the commit being pushed.

git rev-parse HEAD
7e358a0720e93027cf59f6f4fd4636226c14f9ea

git show HEAD:src/lifecycle/mod.rs | grep -n 'every_field_name_the_core_emits'
499:pub const fn every_field_name_the_core_emits() -> &'static [FieldName] {

git grep -c 'FieldName::' HEAD -- src/
HEAD:src/cache/bound.rs:5
HEAD:src/cache/envelope.rs:4
HEAD:src/diagnostics/mod.rs:7
HEAD:src/diagnostics/redaction.rs:5

The last two of those four are inside their own file's test module and the
scanner skips them, which is what the module documentation on that test file says
and what the second case below is about.

cargo test --locked --test the_rule_as_data_names_every_field
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

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

cargo test --locked | grep -c '^test result: ok'
10

The gate legs that need no network on this machine:

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

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

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

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

bash .github/excluded-targets/excluded-targets.sh check | tail -1
Every target the ordinary command leaves out compiles.

What a guard here refuses, and the proof it bites

Four deliberate violations, each run with
cargo test --locked --test the_rule_as_data_names_every_field. The green run is
the one above: 5 passed, 0 failed.

THE ONE THIS EXISTS FOR: a subsystem declares a name and does not register
it.
A tenth name was added beside the nine in src/cache/bound.rs and nothing
else was touched:

test result: FAILED. 4 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out
every_name_the_tree_declares_is_in_the_statement ... FAILED
declared in the tree and absent from 0071's statement: ["a-name-somebody-added"]

A registered name dropped from the statement, which is the same failure
arriving from the other side. bound::SUSPENDED_FOR was removed from the list:

test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out
every_name_the_tree_declares_is_in_the_statement ... FAILED
declared in the tree and absent from 0071's statement: ["suspended-for"]

The statement naming one field twice, which is where a name and a treatment
could disagree inside one list:

the statement names released-bytes twice

The one reduced field replaced by a carried-whole one, which is the pair
0071 says comes apart:

test result: FAILED. 2 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out

And the skip the scanner rests on was watched failing on the tree itself, on
its first run.
It began as "everything after the first #[cfg(test)] in a
file", and no_source_file_carries_more_than_one_test_module went red at once:

G:\Github\core\src\cache\mod.rs carries 2 test blocks, and this file skips from the first one on

The second occurrence is the attribute mentioned inside a doc comment, in that
file and in two others. Taking the string anywhere would have cut three files off
above their declarations and reported a green run over source it never read. What
is matched is a line that is exactly #[cfg(test)] at column zero, and the case
now asserts no file carries two of those, so the skip cannot quietly widen.

What this does not cover

Two of #71's three conditions. The rule being recorded is met by 0071 and was
before this. A test driving a full session at the most verbose level and
searching the output for every named personal field needs a session, a transport
and a sign-in, none of which exists.

Whether a treatment is the RIGHT one for a name. That is 0068's judgement,
no reading of this tree makes it, and src/diagnostics/redaction.rs already says
so of itself. Everything here is about the name and the treatment agreeing, never
about the treatment being correct.

A name assembled rather than written as a literal. The three constructors
take a &'static str and every declaration in this tree passes a literal, so the
scanner finds them. One built some other way is invisible to it, and would also
be a departure from what 0071 says a name is.

The statement is what THIS BUILD emits and is not a promise about a client's
sink.
0071's own sentence, and it is in the doc comment rather than only here.

No field this build emits is excluded. 0071 puts the session token and
anything derived from it under that treatment and nothing in this tree emits one
yet, so a bundle assembled today holds a correlator for one field and nothing at
all for none. The case that reads the set asserts that emptiness rather than
passing over it, so the day an excluded field arrives it is a red run and a
decision rather than a silent change to what a bundle says.

Two files outside this change's own subject were touched, and they are
src/cache/bound.rs and src/cache/envelope.rs. What changed in each is the
visibility of the field-name constants, from private to crate-visible, with no
change to a value, a name or a treatment. #42 and #105 own those files and
neither is moved by this.

The targets and thread-detector legs did not run here. One needs cross
toolchains this machine has not set up and the other a nightly compiler it does
not carry.

Nothing was run that could raise a consent prompt on this machine.

Who has read it

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

)

0071 refuses a diagnostics bundle assembled by the core: 0068 and 0100 both fix
that an event is handed over and forgotten in the same call, so there is no
store of past events here to assemble one out of. What that record asks for
instead is the rule as data - for each field name the core has ever emitted,
which of the three treatments it applies - so a client assembling a bundle out
of what its own sink kept can include the statement verbatim and whoever is
about to send it can read what is not in it. Nothing in the tree produced it.

`lifecycle::every_field_name_the_core_emits` is that statement. It is gathered
there because a field name lives beside the event identity that carries it,
which is 0100's placement and what 0071 wants, so the only place that sees all
of them is the one that sees every subsystem, which 0115 makes creation. The
nine names two cache modules declare become visible to the crate and to nothing
outside it.

The one way that statement can be wrong in the direction that matters is by
being SHORT. A subsystem can declare a name and emit it while the gathered list
does not move; the statement is then incomplete and goes on reading as complete,
and a bundle carrying it tells somebody a value is not in their events when it
is. Nothing inside the crate can catch that, because a missing entry is a
shorter array rather than an error.

tests/the_rule_as_data_names_every_field.rs is what catches it. Its subject is
the source read as bytes, which is why it is out there rather than in the crate:
`no-filesystem-access` refuses `std::fs` under `src/`, and reading the tree is
exactly what this has to do. It compares the names declared outside every file's
own test module against the statement in both directions, and it checks that the
treatment stated for a name is the one its declaration gave it, which is 0071's
own reversal condition.

The skip that test rests on is narrower than it looks and it was watched
failing: taking the string `#[cfg(test)]` anywhere cuts three files off above
their declarations, because each mentions the attribute inside a doc comment, so
what is matched is a line that is exactly that at column zero, and a case
asserts no file carries two of them.

Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com>
@iderex
iderex merged commit d57446d into main Sep 2, 2026
27 checks passed
@iderex
iderex deleted the the-rule-as-data-every-field-name-carries-71 branch September 2, 2026 18:01
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