Skip to content

Mikegrier/probes encoded row contract - #89

Merged
MikeGrier merged 46 commits into
mainfrom
mikegrier/probes-encoded-row-contract
Sep 14, 2026
Merged

MikeGrier merged 46 commits into
mainfrom
mikegrier/probes-encoded-row-contract

Conversation

@MikeGrier

Copy link
Copy Markdown
Owner

No description provided.

Mike Grier and others added 28 commits September 12, 2026 18:34
…nd re-plan M2

M2 built a report oracle that reads the RENDERED TEXT and checks the prose half
against the NDJSON half. Its charter said that had to be so: "checking state
would miss precisely this defect class -- in the original finding the state was
consistent and the two renderings of it were not."

Re-checked against the code, that sentence is wrong about its own evidence, and
both defects it rests on were defects in the encoded row.

**The alarm beside the agreeing verdict.** The alarm is a `writeln!` into the
prose and the row has no key for it, while `cross_check` IS a key and read
`agree`. So the row certified a clean agreeing measurement on a host where the
probe had detected its own bug. A survey mining it would have been wrong with no
way to know. The prose alarm was not the defect -- it was the only trace that the
row was, which is why a human found it and no instrument did.

**`efficiency classes: [0]` against `"efficiency_classes":1`.** Both halves were
correct derivations of one consistent value. Note how it was repaired: the row
now publishes the set. The fix was to change what the row publishes; the prose
comparison was how a reviewer noticed, not the repair.

**A correction made while writing this up, and it strengthened the case.** The
first draft said the alarm's condition is unpublished so the verdict can still
read `agree`. Checked before committing: the second half is no longer true --
`cross_check` now pushes `SummaryMissing` onto `parse_incomplete`, which forces
the verdict away from `agree`. Writing a superseding decision against code as it
used to be would have been the exact defect class this branch spent fifteen
review rounds on.

What the check found instead is live and larger. The row publishes
`not_compared`, `parse_incomplete` and `enumeration_anomalies` as COUNTS, where
the prose prints each entry's text. A survey reading `"parse_incomplete":1`
cannot tell a probe self-bug from a self-contradicting core record from an
unmeasured topology. The row is impoverished relative to the prose: the artifact
that gets mined carries less than the artifact that gets read.

So the decision recorded here is that they are not peers. The row must be
CORRECT, machine-enforced. The prose must be ACCURATE AND READABLE, enforced by
review. Nothing is required to hold between them.

Counted, for what the other reading cost: of 38 top-level functions in
report_oracle.rs, ten are correspondence rules and four are comparison helpers
-- twenty-three exist only to extract values back out of rendered text. That is a
parser for a format this crate writes, and it behaved like one: a large share of
PR #88's review rounds were defects in the reader rather than the thing read.

M3 queues the work in dependency order: publish each diagnostic as itself rather
than as a count (M3.1); relocate the three surviving correspondences onto the
observation as invariants checked before rendering (M3.2); emit the row from a
typed value through one writer, which makes injection and field-order defects
unrepresentable and subsumes the typed-banner question (M3.3); retire the
prose-against-row family and its extraction layer, keeping only a well-formedness
check on the row (M3.4); re-aim the corpus and fact accounting at the row's
fields (M3.5); and split DESIGN-NOTES.md, now 88 KiB and XL, into Tier 1 and
Tier 2 (M3.6).

M2.18 is dissolved into M3.3 rather than answered alone -- it was the smallest
instance of the same question. M2.17 is re-scoped by M3.5 and should follow it,
since crossing prose shapes that are about to stop being checked aims at the
retiring half. The nine remaining M2 items are unaffected.

Supersedence markers are adjacent to both affected decisions, and the earlier
one keeps everything about it that still holds -- what the oracle admits, the
acceptance half, and the failure mode that looks like success.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ount

Completed item: M3.1: Publish each diagnostic as itself, not as a count.

The row published `not_compared`, `parse_incomplete` and `enumeration_anomalies`
as `.len()`, so it said a run was in doubt without saying why. A survey reading
`"parse_incomplete":1` could not tell `partitioning_summary_missing` -- this
probe detecting a bug in ITSELF -- from `contradictory_cores` or `not_measured`.
Four categorically different facts, one cardinality, and only the prose
separated them.

That is the gap recorded in DESIGN-NOTES.md -> #d-encoded-row-is-the-contract:
the row was impoverished relative to the prose, which is backwards given that
the row is what a fleet survey mines and what the designs rest on.

**The vocabulary is now three enums** in `topology::diagnostic` -- 21
`ParseIncomplete`, 6 `NotCompared`, 3 `Disagreement` variants, one per condition
that `cross_check` can report. Each carries its own data, renders its own
sentence through `Display`, and names itself through `code()`. `CrossCheck`'s
three `Vec<String>` became `Vec<Diagnostic>`, and all 30 push sites construct a
variant rather than formatting a string.

One definition, so the code and the sentence cannot drift apart -- where a
parallel `(code, String)` pair could be updated on one side only.

**The code is the contract; the sentence is not.** Changing a `code` is a
breaking change to the row, exactly as renaming a field would be. The `Display`
text reaches only the prose, where a reader is the consumer and rewording is
harmless. That is what lets the prose be written for a human: before, a test or
a survey wanting to know which condition fired had to match on English, which is
a reason not to improve it. 34 assertions did exactly that and now match on the
variant.

**The wire format changed, deliberately and not additively.**
`"parse_incomplete":1` is now `"parse_incomplete":["partitioning_summary_missing"]`.
The count is still available as the list's length, so nothing is lost, and
publishing both would be a restatement that can drift. Same correction, and the
same argument, as the `efficiency_classes` count-to-list change that preceded
it. Marked `!` for that reason: any consumer reading those three fields as
numbers must change.

The prose is byte-identical. The renderer's loops write `{entry}` and `Display`
emits the sentences that were there before.

**Which conditions are listed is deliberately not compared against the prose,
and needs no rule.** The code and the sentence come from one variant, so there
is no second implementation for them to disagree through: the correspondence
holds by construction, which is stronger than a check. What remains checkable,
and is checked, is that both renderings list the same NUMBER.

That was found rather than assumed. Converting the accounting instrument, a
mutation that swapped one code for another went unnoticed on the
`verdict incomplete` corpus shape -- because the oracle reads the length, and a
one-element list rewritten to a different one-element list has the same length.
`corruptions` now APPENDS a code instead of substituting one, so the length
differs by one whatever the host rendered.

`ndjson_count` was retired rather than left unused: with the three fields now
lists, it had no remaining consumer, and a dead reader is a second grammar for a
format that no longer has two.

Verified. 249 lib tests plus 14 ignored, 9 integration tests and doctests, on
both `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`. Workspace
`cargo check --all-targets` clean in debug and release, `cargo doc` clean under
all three rustdoc deny lints, clippy --all-targets --all-features clean, fmt
clean, encoding clean over 635 files. A real `probe-topology` run emits
`"not_compared":[],"parse_incomplete":[],"enumeration_anomalies":[]`.

The four new tests were each observed to fail, with the mutation injected on its
own line and reverted: renaming `PartitioningSummaryMissing`'s code reddens only
`the_row_names_the_probes_own_bug_when_it_detects_one`; making the row keep only
the first condition reddens both list tests, through the bound oracle's count
rule; mislabelling `TrailingBytes` reddens only
`an_anomaly_reaches_the_row_as_its_kind`.

Swept the claim this change falsified: DESIGN-NOTES.md stated in two places that
the row publishes `parse_incomplete` as a count, and M3's checklist preamble
stated it as a present gap. All three corrected in this commit rather than left
to be found later. The design-session record keeps its present tense, being a
dated account of that session.

`AnomalyKind` is `#[non_exhaustive]`, so `anomaly_code` needs a catch-all and a
variant added upstream lands in it. That is stated rather than hidden:
`unclassified` means "this probe's vocabulary is older than the crate's", which
is more useful to a survey than a code invented here that pretends to name the
new kind. Deliberately not a compile error -- owning the row's vocabulary means
this crate decides when a new upstream kind earns a code.

M3.3 picks up what this left: the row carries a condition's code but not the
values its variant holds, because the row is still a positional `concat!`
template where a nested per-entry object has to be hand-assembled. Queued there
rather than dropped, and the blocker is the row's shape, not the want of a
consumer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nate

A review of the M3.1 change set found two tests that had stopped testing what
they are named for, and three stale statements.

**The substring-to-variant conversion dropped what the substring discriminated.**
`both_absent_counts_are_named_together_rather_than_one_standing_for_the_pair`
became `matches!(c, MeasuredButCountsAbsent { .. })`, which holds when `absent`
names only ONE of the two counts -- exactly what the test forbids. Measured: with
`absent` truncated to its first entry, the whole suite stayed green at 249
passed, so the test could not fail for its own property and was fully subsumed by
the loop above it.

The same conversion took the discrimination out of
`a_measured_topology_reporting_no_processors_or_groups_blocks_agreement`: its
loop labels had BEEN the assertion (`c.contains(label)`) and became captions for
the failure message, so neither iteration checked that the correct count was
named.

Both now assert the variant's payload, and both were observed to fail:
truncating `absent` reddens the both-absent test, and swapping the two names in
`cross_check` reddens both.

The general lesson, recorded in the checklist: converting an assertion from a
substring to a variant DROPS whatever the substring discriminated inside the
payload. The variant is the weaker claim unless the payload comes with it.

**Swept the class rather than the reported instance**, which found one more --
`an_empty_core_or_package_record_blocks_agreement`, where both arms raise
`RelationsWithoutProcessors` and the variant match cannot separate an empty CORE
record from an empty PACKAGE one. That gap PREDATES this branch: `Display`
renders `{cores} core(s) and {packages} package(s) cover no processors` as one
sentence, so the old `"core(s) and"` and `"package(s) cover no processors"`
substrings both matched whichever field was set. Fixed here because it is the
same class as the two above, and verified the same way: swapping `cores` and
`packages` at the construction site reddens it.

Reviewed the other thirty-odd conversions against this: the rest map to distinct
variants whose identity is the whole claim, and the one that did carry a payload
distinction -- `contains("none")` for a missing NUMA node -- kept it as
`HighestNumaNode { parsed: None, .. }`.

**Three stale statements**, each made false by the commit before this one and
each verified against the code:

- Both `PLANS.md` trackers still said the row publishes its diagnostic lists as
  bare counts, in the present tense. They were written before M3.1 landed and
  were not swept with DESIGN-NOTES.md and CHECKLIST.md, so they contradicted the
  code and three sibling documents.
- `report_oracle.rs` carried the deleted `ndjson_count`'s summary line orphaned
  above `ndjson_list_len`'s own, so rustdoc rendered a two-sentence summary whose
  first half described a function that no longer exists.
- DESIGN-NOTES.md and CHECKLIST.md M3.3 both said the row interpolates
  "eighteen values" positionally. Counted: the template has seventeen `{}`
  placeholders and takes seventeen arguments -- `reason` is a literal. Since the
  sentence's point is the hazard of a miscounted placeholder, the placeholder
  count is the one it should quote. The session record's "eighteen keys" is
  correct and unchanged.

Verified: 249 lib tests plus 14 ignored, 9 integration tests and doctests.
clippy --all-targets --all-features clean, fmt clean, cargo doc clean under all
three rustdoc deny lints, encoding clean over 636 files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A review found the list M3.1 built a vocabulary for and never wired.
`Disagreement::code()` had ZERO production callers: the row carried
`cross_check`, `not_compared`, `parse_incomplete` and `enumeration_anomalies`,
and no `disagreements` field at all -- while the prose listed each disagreement
with both readings.

So a survey could see `"cross_check":"disagree"` and could not tell WHICH
counter contradicted the parse, or whether several did. That is the same shape
as the defect this milestone came from, in the one list nobody had noticed was
missing, and it breaks the rule M3.1 itself established: a renderer may not tell
a reader something the row cannot tell a survey.

The gap predates the milestone -- `disagreements` was never in the row, not even
as a count -- but M3.1 is what made it a stated violation rather than an
omission, and M3.1 converted all three lists while wiring two.

**Why every instrument here missed it, which is the durable finding.** The fact
accounting enumerates the ROW's keys and requires each to be classified, so it
asks "does anything read this key?" and never "does the prose state a fact the
row omits?". A fact with no key is outside the set of things it can have an
opinion about. The mutation sweep has the same orientation: it perturbs code the
row's construction reaches. Between them they survived 41 review rounds and a
zero-survivor sweep on this exact omission. The reviewer found it by reading the
enum and asking who called `code()`.

Recorded in DESIGN-NOTES.md as a limit of what the instruments cover -- the rule
is a convention, not a checked property, until the second enumeration exists --
and queued as M3.5, which owns the accounting.

The row now publishes `"disagreements":[...]`, and two rules read it:

- The DISAGREE arm counts them against the prose's bare `- ` lines, symmetric
  with the two tagged kinds it already counts. That arm labels each kind, which
  is why it can separate all three where the INCOMPLETE arm can only sum.
- The agreeing-verdict alarm covers it, and more directly than the other three:
  a non-empty `disagreements` makes the verdict `Disagree` by construction, so
  an agreeing row publishing one contradicts `CrossCheck::verdict` itself rather
  than a rule about what `agree` implies.

Marked `!` for the same reason as M3.1: the row gained a key, and a consumer
asserting on its shape must change.

Two existing tests went red on the way, both correctly. An oracle fixture listed
a disagreement in prose with no `disagreements` in its row, which is now the
violation it looks like; and the accounting had nothing reading the key on an
INCOMPLETE shape, which the same `AtValueUnlessAgreeing("[]")` classification
`enumeration_anomalies` already carries resolves -- at `[]` there is no second
rendering, and under `agree` a non-empty list is a violation in its own right.

Sabotage-verified: with the row publishing an empty list unconditionally,
`the_row_names_which_counter_disagreed` fails through the bound oracle.

**Swept the placeholder count this change falsified, and stopped quoting it.**
DESIGN-NOTES.md and CHECKLIST.md said the template interpolates "eighteen
values"; a review corrected that to seventeen this afternoon; adding
`disagreements` made it eighteen again within the hour. Both now state the
coupling instead -- a field's name and its value are related only by counting
positions -- which is the hazard the sentence is actually about and cannot rot.
That is M2.14's first authoring rule, learned for the third time on the same
sentence.

Verified: 251 lib tests plus 14 ignored, 9 integration tests and doctests, on
both `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`. clippy --all-targets
--all-features clean, fmt clean, cargo doc clean under all three rustdoc deny
lints, encoding clean over 636 files. A real `probe-topology` run emits
`"cross_check":"agree","disagreements":[],"not_compared":[]`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ff the text

Completed item: M3.2: Assert the surviving correspondences as invariants on the
observation, before rendering.

The correspondences worth keeping were never really about rendering. They relate
a STATE to the verdict, and the report is only where that relation first became
visible. `topology::invariant` states them as predicates over `Observation`, so
they run whether or not anything was rendered and no parser stands between the
rule and the values it reads.

**The first attempt was wrong, in a way worth recording because it is not
obvious.** It had four rules, two of which read `CrossCheck`'s lists: "a
non-empty `parse_incomplete` forbids `agree`", and the same for
`disagreements`. `CrossCheck::verdict` is a pure function of those three lists,
so both are restatements of its definition -- they cannot fail for any input,
and three of the tests written for them asserted acceptance under
violation-sounding names, which is the exact defect this branch has been fixing
all day.

Worse than useless: a list-reading rule **cannot catch the defect this component
exists because of.** That defect was a state -- a named partitioning level with
no summary -- that `cross_check` had no branch for. A missing branch leaves the
list EMPTY, so a list-reading rule sees nothing and the verdict it produces is
`Agree` legitimately. The evidence survives only in the observation.

So every rule now reads the observation. `blocking_states` names ten states that
forbid an agreeing verdict -- the summary-missing bug, recorded anomalies, an
unmeasured topology, no caches, no packages, no cores, a self-contradicting core
record, a cache level numbered 0, enumerations that did not agree, a bracket
that did not hold -- each computed from the observation, each with a push site in
`cross_check` that it does not consult. Plus the two counter rules: `agree`
asserts every check was MADE, so a counter that reported failure or disagreed
cannot sit beside it.

`check` takes the VERDICT rather than deriving it. That is not a convenience:
`cross_check` is what makes these hold, so no observation can violate them while
it is correct, and a derived version would leave every branch reachable only by
editing the source -- a green run carrying no information. Supplying the verdict
lets a test hand over the answer a broken `cross_check` would give.

Bound at two places, covering different things. `observe` covers every
observation this crate MEASURES, rendered or not, which is what the item asked
for. `report` covers every observation anyone RENDERS, which on the test side is
most of them, since the suite builds observations by hand rather than measuring
a machine. Never in `cross_check`: `assert_holds` asks it for the verdict, so
the assertion would recurse.

Sabotage-verified on the push site that matters. Deleting the
`PartitioningSummaryMissing` push from `cross_check` -- the fix for the
originating defect -- reddens four tests, two of them new: the invariant's own
`every_blocking_state_is_one_the_real_cross_check_already_reports`, and
`the_row_names_the_probes_own_bug_when_it_detects_one` through `assert_holds` at
the renderer binding. The other two are pre-existing verdict tests, so the
invariant is not the sole detector for THIS push site; its value is the nine
others, several of which have no dedicated test.

`every_blocking_state_is_one_the_real_cross_check_already_reports` is the test
that keeps this a postcondition rather than a second opinion: for each state,
the verdict the crate actually draws must ALREADY be something other than
`agree`. If one ever fails, the answer is to fix `cross_check`, not to relax the
invariant.

Verified: 260 lib tests plus 14 ignored, 9 integration tests and doctests.
clippy --all-targets --all-features clean, fmt clean, encoding clean over 636
files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ting at the row

Completed items: M3.4, M3.5

Completed item: M3.4: Retire the prose-against-row correspondences and the
parsers that serve only them.
Completed item: M3.5: Re-aim the shape corpus and the fact accounting at the row.

**Committed together because they cannot be separated.** The fact-accounting
instrument is built entirely on `report_oracle::check` and the `Correspondence`
variants, so deleting the correspondences leaves it measuring nothing and the
suite red between the two items. Splitting would produce a commit that does not
pass, which the checklist rules call the worse defect.

`report_oracle` read the report's PROSE, extracted values back out of the
rendered sentences, and compared them against the NDJSON row.
DESIGN-NOTES.md -> #d-encoded-row-is-the-contract retired that: the row is a
machine contract and the prose is for a reader, they carry different
obligations, and nothing is required to hold between them.

Measured. `report_oracle.rs` 79,394 -> 8,874 bytes; its tests 105,299 -> 5,598;
the integration instrument 71,007 -> 25,689. All eight prose correspondences and
all twenty-three extraction helpers are gone -- a parser for a format this crate
itself writes, which behaved like one: a multi-byte panic, a substring matching
inside an opaque `io::Error`, a `trim_matches` collapsing `[[0]]` and `[0]`.

What survives is the writer's own output read back, which is the one thing no
amount of typing upstream can do for itself: exactly one machine-readable line,
brackets balanced, no repeated top-level key. The balance check is string-aware
because a failed discovery's `io::Error` is interpolated into a string value and
an OS message is free to contain a bracket -- a naive counter would report every
such host as malformed. The repeated-key check is there because that
malformation survives a consumer's parse and silently changes what it reads.

**The key-set check is deliberately not here.** Asserting it needs a list of
expected keys, and a list written here is a census -- this component
re-corrected the same census three times in one day. M3.3 makes the row a typed
value, at which point the set is derivable from the type. Moved there rather
than approximated now.

**The accounting now enumerates in the direction the rule lives in.** It no
longer asks "which prose facts does the oracle read"; it asks, for every state
`topology::invariant` knows forbids agreement, whether the row publishes a
condition for it -- and holds the prose's diagnostic line count against the row's
condition count across the corpus. That is the enumeration whose absence let
`disagreements` reach the prose and not the row at all, surviving 41 review
rounds and a zero-survivor mutation sweep.

Sabotage-verified against exactly that: dropping `disagreements` from the row
reddens `the_row_lists_a_condition_for_every_diagnostic_the_prose_lists`.

**One asymmetry, found by the instrument rather than reasoned.** Counting all
four lists against prose lines failed on the anomaly shapes: the prose folds
every anomaly into ONE sentence while the row lists one code per anomaly, so
three anomalies read as two dropped entries. `enumeration_anomalies` counts on
its own axis, checked against the OBSERVATION -- one published code per anomaly
recorded -- which is the artifact the row owes fidelity to. Checking it against
the number inside that sentence would be the prose-reading this milestone
retired.

Both publication rules carry a corpus guard, because both skip a shape in no
blocking state and a drifted all-healthy corpus would leave them green while
checking nothing. The corpus itself, its shape builders and the real-host render
are unchanged.

Marked `!`: `report_oracle`'s public surface is replaced. `Correspondence`,
`check`'s return type, `architecture_in_banner` and the extraction helpers are
gone, and `check` now returns `Vec<RowDefect>`.

Verified: 184 lib tests plus 14 ignored, 9 integration tests and doctests.
clippy --all-targets --all-features clean, fmt clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…riter

Completed item: M3.3: Emit the row from a typed value through one writer.

The row was built by interpolating every value positionally into a `concat!`
template. Two defect classes follow from that construction, and both are closed
by replacing it rather than by checking it.

**Injection.** Measured on PR #88: an `io::Error` whose text contained `{` was
selected as the report's machine-readable row, so a reader checked the caller's
text instead of the probe's. A `Value::Text` is escaped by the writer, so no
string it carries can end the string it is in, let alone start a new row.

**Field order and labelling.** A field's name and its value were related only by
counting positions, so a reordered argument or a miscounted placeholder yielded
mislabelled data that still parses and that nothing downstream can detect. Here
a name and its value are one pair, moved together or not at all.

`crate::row` holds the value model and the single writer. The escaping is
deliberately total -- quote, backslash, newline, carriage return, tab, and every
control character below a space -- because the text it carries is whatever the
OS said, and each of those alone would end something.

**Each diagnostic publishes its DATA**, not only its code:
`{"code":"contradictory_cores","count":3}`. That is what M3.1 had to leave
behind, and the blocker it named was exactly this template. Anomalies carry
`source` and `offset` as well as kind, because the same kind at the same offset
across a fleet is a different finding from the same kind scattered, and neither
is visible from a count.

`report_unmeasured` goes through the same writer, and it is the shape that most
needed it: the only renderer that interpolates caller text. The error now
reaches the row as a `discovery_error` field, so a survey can group failures by
cause rather than parsing the prose sentence -- which is the rule M3.1
established, applied to the one fact this renderer has.

**The key-set check M3.4 deferred to here now exists, derived.** `Row::keys`
reads the value, and a test asserts that the reader and the writer agree. M3.4
declined to assert a key set because a list written beside the check is a census
-- this component re-corrected the same one three times in a day and the last
correction was falsified within the hour. A derived set cannot rot.

**Two silent behaviour changes were caught by checking the old code rather than
trusting the rewrite.** `PartitioningCache` has FIVE variants, not the four a
rewrite naturally reaches for -- `NoUniqueOutermost` was missing -- and
`SummaryMissing` publishes its LEVEL rather than `null`. The second matters
precisely because that arm is the report telling a reader this probe has a bug,
and which level went unchecked is what they need. Both recovered from
`git show HEAD:...` before the conversion was believed.

Sabotage-verified: removing the quote escape reddens three row tests, including
the brace-injection one. The clean row is byte-identical to what the template
produced, confirmed against a real `probe-topology` run.

`list_codes` and `list_span_end` are shared from `report_oracle` rather than
copied into the two instruments that need them. The diagnostic entries are
objects now, so reading them means finding each `code` member rather than
splitting on commas -- and a comma-splitting sabotage inside the accounting broke
silently when this landed, which is the argument for one definition: a sabotage
that no longer sabotages leaves the rule it guards unguarded while still passing.

Marked `!`: every diagnostic list's entries change from strings to objects, and
the unmeasured row gains a field.

Verified: 202 lib tests plus 14 ignored, 9 integration tests and doctests, on
both `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`. Workspace
`cargo check --all-targets --release` clean, `cargo doc` clean under all three
rustdoc deny lints, clippy --all-targets --all-features clean, fmt clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t matrix

M3.5 left one site where the test matrix obtained structured data by reading
sentences: a rule that filtered rendered lines by prefix, counted them, and
compared that number against the row's condition count. A wider sweep found it
had a unit-test twin in `src/tests.rs` that the first pass missed.

Both are replaced by the same claim stated against `cross_check`: the row's
condition codes must EQUAL the cross-check's, in order.

Strictly stronger. A count catches only a dropped entry; this catches a drop, a
reorder and a substitution. It also covers all three lists, which the prose
count could not -- under INCOMPLETE the renderer gives `not_compared` and
`parse_incomplete` the same bare `- ` prefix, so only their total was
recoverable from prose at all.

Be clear about what it is, since the replacement is easy to over-read: the row
is BUILT from these lists, so this is the writer checked against its input, not
an independent reading of the machine. That is the check worth having -- the
writer is the one thing no amount of typing upstream can check for itself -- but
it is narrower than "the report is correct" and the comments say so.

**The ordering half was vacuous, and the guard is what found it.** Reversing the
row's `parse_incomplete` order reddened nothing: every corpus shape varied one
dimension, so each landed at most one entry per list, and a one-element list has
no order to get wrong.

The first version of the guard summed the three lists and passed while the
sabotage still did nothing -- one entry in each of two lists is two conditions
and no order to get wrong. Corrected to measure the largest SINGLE list, and a
`several conditions at once, in one list` shape added to the corpus. The reorder
now reddens `the_row_lists_exactly_the_conditions_the_cross_check_found`.

That sequence is the point of the guard: a corpus cannot report the shape it
does not reach, so the rule looked strong for as long as nothing asked it to
prove it.

Swept for the claim rather than asserting it. What still touches rendered text:
selecting the row line, and positional containment -- the banner is the first
line, the banner is one line, there is exactly one row-shaped line. None reads
prose for its content, and no test parses prose into a value.

The 58 `contains(...)` assertions on prose remain and are deliberate: they test
the prose renderer on its own terms, which the decision permits. They extract
nothing.

Verified: 202 lib tests plus 14 ignored, 9 integration tests and doctests, on
both `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`. clippy --all-targets
--all-features clean, fmt clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Completed item: M3.6: Split DESIGN-NOTES.md into Tier 1 and Tier 2.

DESIGN-NOTES.md was 92,467 bytes -- XL on the repository's byte scale, where the
default answer is to split unless the document is indivisible. It is not: it
carried current decisions and a large block of how-we-got-here reasoning, which
is exactly the Tier 1 / Tier 2 fracture.

The fracture taken is the correspondence-oracle investigation: the two defects a
pull-request review found after twenty-eight rounds of per-artifact review and a
zero-surviving-mutant sweep, why each instrument was structurally incapable of
seeing them, the sparse-matrix-and-oracle split that followed, and the oracle's
own design, failure modes and mutation evidence.

It is Tier 2 on both tests. It records how a decision was reached rather than
stating one, and the decision it reached has since been superseded by
#d-encoded-row-is-the-contract.

Moving it also resolved latent drift rather than only relocating bytes. The
block cites the `Correspondence` enum, the fact-accounting instrument and the
prose correspondence rules -- none of which survived M3.4 and M3.5. As history
those sentences are accurate; sitting in Tier 1 they described deleted code as
though it were current.

**The result is still XL, and that is stated rather than implied away.**
DESIGN-NOTES.md is 67,807 bytes, over the 64 KiB threshold. The split was made
at the one unambiguous fracture rather than trimmed until it hit a number: a
cut sized to a byte budget yields two documents that are each individually
incomprehensible, which is worse than one large coherent document.

Why it stays over: the remaining bulk is neither current decisions nor
rationale, but FINDINGS -- measurements about Windows that are this crate's
actual product. They do not belong in a rationale file, and filing them as
decisions is what keeps Tier 1 large. Whether they want a tier of their own is a
structural choice about this component's documentation scheme, so it is raised
as an open question on the checklist rather than taken unilaterally.

Pure relocation, verified byte-for-byte against the pre-split file: 439 lines,
identical. No reflow, no rewording, no other work in this commit -- the two
headings missing a blank line above them were inherited and are left for a
follow-up, because a split that also tidies is a split whose blame cannot be
traced.

The two moved anchors are kept in Tier 1 beside a pointer, so an existing link
to `DESIGN-NOTES.md#d-correspondence-failures` still lands somewhere that says
where the content went. Every in-repo reference was repointed at the content
itself: the superseding decision's two links, the design-session record's two,
and the crate's PLANS.md row.

Split-Source: crates/windows-platform-probes/DESIGN-NOTES.md
Split-Into: crates/windows-platform-probes/DESIGN-RATIONALE.md
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A review of the branch found eight issues. The first is a real defect, reachable
through a public renderer, and the rest are claims that outlived the code.

**`report_oracle::keys` was not escape-aware, and a correct report crashed the
probe.** `balanced` tracks `in_string`/`escaped`; `keys` walked quote to quote
with `find('"')` and took `\"` for a terminator. The row legitimately carries
caller text -- `report_unmeasured` publishes a failed discovery's `io::Error` as
`discovery_error` -- and an OS message may contain a quote. When it does, the
reader's idea of where strings begin and end shifts, text INSIDE the value is
emitted as top-level keys, and two equal ones are reported as a repeated key.

Measured, not reasoned: `report_unmeasured` given `io::Error::other("q\":1,\"q\":1,\"q")`
renders a row that parses cleanly with four keys, and `assert_corresponds`
panicked FROM INSIDE THE RENDERER -- `report_oracle.rs:295`, reached through
`report_unmeasured`'s own binding. Under `cfg(test)` or `oracle-in-renderer`
that is a correct report crashing the probe, which is the failure mode the
containment work exists to prevent. The writer was never at fault; the reader
disagreed with it.

`keys` now shares the state machine through `string_end`, and two tests cover
both directions -- an escaped quote inside a value, and a value ending in an
escaped backslash, which getting wrong the other way would silently drop every
key that follows.

The same hazard does not reach `list_codes` or `list_span_end`: those scan the
diagnostic lists, whose entries carry only codes minted in this crate and
numbers. No caller text reaches them.

**A completeness guard that was documented and did not exist.**
`perturbations()` said "the interesting part is that NONE of them is missing --
which the count assertion below states as a relation". There was no such
assertion. The table happened to match `blocking_states`' ten states, which is
the condition under which nobody notices. `every_blocking_state_has_a_perturbation`
now derives the reached set by applying every perturbation and compares it
against the table's labels in both directions, so a state added to the invariant
with no entry fails rather than going unexercised. Derived rather than counted,
because a census needs correcting every time a state is added.

**A test whose name asserted the opposite of its assertion.**
`a_defect_is_reported_once_per_repeated_key_rather_than_per_occurrence` claimed
de-duplication the code does not do while asserting the per-occurrence behaviour
its own failure message describes. The assertion was right; the name and comment
were the defect. Renamed to `..._once_per_extra_rendering_of_a_key`.

**Four statements that outlived the code they described**, each verified against
the tree before correcting:

- DESIGN-NOTES.md said the three fields "publish arrays of condition codes" with
  a bare-code example. True at M3.1; M3.3 gave each entry its data three commits
  later on the same branch, so the published form is an object. Tier 1 is where
  a reader goes for the wire format, so it is the one place that must be right.
- CHECKLIST M3.5 said the instrument "holds the prose's diagnostic line count
  against the row's condition count", and cited a sabotage against
  `the_row_lists_a_condition_for_every_diagnostic_the_prose_lists`. Both were
  invalidated by the follow-up commit recorded further down the same item, which
  removed the prose count and renamed the test -- so the item disagreed with
  itself and its evidence could not be re-run as written. The sabotage was
  re-run against the current name to confirm it still reddens.
- DESIGN-RATIONALE.md said the oracle section "still describes what is in the
  tree and still holds", then listed three rules M3.4 deleted. True when
  written, carried through the Tier 1/Tier 2 split unchanged.
- Three same-file anchor links in DESIGN-RATIONALE.md still pointed at
  `#d-encoded-row-is-the-contract`, which the split left in DESIGN-NOTES.md.

**One doc comment attached to the wrong item.** Two comments had merged onto
`codes_of`, so the paragraph warning against asserting on the struct sat above
the helper that reads the struct. Moved to `row_codes`, which had none.

Verified: 205 lib tests plus 14 ignored, 9 integration tests and doctests, on
both `x86_64-pc-windows-msvc` and `i686-pc-windows-msvc`. clippy --all-targets
--all-features clean, fmt clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A review of the completed M3 found no wrong behaviour and four weak
instruments -- tests and guards asserting a property they could not fail
to satisfy. Each is recorded with what it was measured to miss.

1. The row's key set was unenforced. M3.3 claimed the check was "derived"
   because Row::keys reads the value and a test holds reader against
   writer -- but both read the same Row, so the test proved only that the
   writer is self-consistent. Measured: deleting .with("packages", ...)
   from the renderer left the entire suite green. Declared
   MEASURED_ROW_KEYS / UNMEASURED_ROW_KEYS as the contract instead. This
   is not the census M3.4 feared: a count is derivable from the thing it
   counts, so restating it invites drift; a schema is not derivable from
   the row, which is why writing it down buys something.

2. The well-formedness oracle accepted invalid JSON. balanced() counted
   bracket depth only, so {"a":1,} and {"a":1] both passed a check whose
   name promised a consumer could parse the row. Replaced with
   malformation(), a typed delimiter stack that also checks separator
   placement; RowDefect::Unbalanced becomes Malformed { what, row } so
   the defect names itself.

3. A sabotage asserted only that it had sabotaged. The publication
   accounting's sabotage stripped a condition from the report and then
   asserted the condition was absent -- a fact about the string edit, not
   about the rule, and it would have passed with the rule deleted. The
   rule is now publication_holds(observation, text), and the sabotage
   asserts it rejects the stripped report and accepts the original.

4. A completeness guard compared a table against itself. blocking_states
   returned strings and the guard derived both sides from that one table.
   Added a BlockingState enum with ALL, so the guard holds the table
   against the type's variants.

Sabotage-verified, each against the instrument it was meant to strengthen:
the dropped field reddens the key-set contract; a writer emitting a leading
separator produces a balanced-but-invalid row that the old check passed and
the new one rejects.

Completed item: M3.7: Make four instruments as strong as their names claim

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The same defect as the previous commit's fourth finding, one level up,
and introduced by the fix for it.

The doc on ALL claimed "an exhaustive list the compiler checks: adding a
variant without adding it there fails to build". That is not what the
compiler checks. The match in described() IS exhaustive-checked, which is
what made the claim look right, but it forces a new variant to acquire an
ARM, never an ENTRY in a separate array.

Measured rather than read: a new variant plus the described() arm the
match demands compiled cleanly and left all ten invariant tests green,
reached by none of them. ALL is the list the completeness guard iterates,
so a variant missing from it is a blocking state nothing tests -- the
exact failure the guard was added to prevent, reintroduced by the shape
of its own fix.

The guard's reverse loop is not a substitute. It catches a state
blocking_states produces and ALL omits, but only once some perturbation
reaches it -- and a state with no perturbation entry is precisely what
the test exists to catch, so it is circular in the case that matters.

Fixed by declaring the enum, ALL and described() from one list through a
macro, so a variant that is not in the list does not exist. The claim is
now true rather than deleted. Corrected the same false claim where it was
restated in the guard's own comment.

Sabotage-verified in both directions: the original sabotage is now
inexpressible, there being no second place to omit the variant from; and
its reachable equivalent, a new state in the list with no perturbation
entry, reddens every_blocking_state_has_a_perturbation where before the
whole suite stayed green.

Three rounds on one guard -- strings, a hand-written ALL, generation.
Each earlier fix moved the census somewhere harder to see rather than
removing it.

Completed item: M3.8: Make `BlockingState::ALL` exhaustive by construction rather than by assertion

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…m bite

M2.14 said "write two authoring rules into the repository instructions".
Measurement says that would have been worse than useless, so the item is
re-planned into two sub-steps before any of it is implemented.

Both proposed rules already exist. CONTRACT INTEGRITY rule 1 in
.github/copilot-instructions.md is "Prefer a derived fact to a restated
one", and beneath it "verify the binding by sabotage: change the
definition and confirm the consumer's BEHAVIOR changes". Those are the
two rules M2.14 proposed. Writing them again would add a second copy of a
rule, which is the exact defect that section forbids and the exact
mechanism, restatement drift, that it exists to prevent.

Statement is also demonstrably not the gap. Both rules were in force
yesterday and both were violated: 09da7e9 claims "Sabotage-verified, EACH
against the instrument it was meant to strengthen" and then names two
sabotages for four fixes. The one that got none is the completeness
guard, found broken by a review an hour later (M3.8). A rule cited in the
commit that breaks it will not be repaired by a third copy of itself.

This repository has solved the problem once already, and not with a rule:
the sabotage-harness CI job records that the harness "accumulated fixes
over eleven review rounds and thirteen of the later defects were
introduced by earlier fixes, because every verification was a one-off
command that was then discarded and nothing re-checked an earlier
guarantee". That is M3.8's story verbatim, and the answer then was a
ratchet.

So M2.14 becomes M2.14.1, give this crate the sabotage.json it lacks
while two sibling crates have one, and M2.14.2, add to rule 1 the single
thing this branch learned that it does not already say -- sabotage the
CLAIM that a weakness was removed, not the symptom -- plus a pointer to
the mechanism. The M2.14 ID is preserved because COMPLETED-CHECKLIST.md
is append-only and two archived entries cite it.

Completed item: M2.14 (re-plan only): Re-plan M2.14 from "write two authoring rules" into M2.14.1 and M2.14.2

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
M2.14.1. tools/run-sabotage.ps1 exists, has its own tests and runs in CI;
windows-placement-probe and windows-waitable-queues each carry a
sabotage.json. This crate carried none, so every sabotage run while
building M3 was ad-hoc PowerShell discarded on the spot -- which is why a
git checkout destroyed uncommitted work twice and a .Replace pattern
silently matched two sites once.

Seven entries, swept green: six caught, one survives, all behaving as
declared. Each is a defect that was actually run by hand during M3, so
this is transcription of verifications that were already made and then
thrown away.

Not wired into CI, matching both sibling manifests and the
sabotage-harness job's note that a sweep rebuilds a crate per entry and
is deliberately an occasional instrument.

The control is the entry that matters most. It rewords a prose line to
carry the same fact and must SURVIVE, which turns this component's
central decision -- the row is the machine contract, the prose is for a
reader -- from a sentence into a measurement. If it is ever reported as
caught, a test has started reading the prose again and that test is the
defect, not the entry.

The harness found a defect in the manifest that the authoring script
missed, which is the lesson worth keeping. The escape-aware key reader
entry anchored on a line that the script judged unique by whole-line
equality; the harness matches by substring and found it twice, because
the same match arm appears in malformation at a deeper indent and the
shallower line is a substring of the deeper one. The script's check was a
second, weaker implementation of the harness's rule -- the exact defect
class this manifest exists to catch. The anchor was widened to the
function signature and the harness left as the only authority.

Completed item: M2.14.1: Give `windows-platform-probes` a sabotage manifest, so "observed to fail" is a recorded artifact rather than a habit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
M2.14.2. Two paragraphs added to CONTRACT INTEGRITY rule 1. Neither
restates the rule, which is what the original M2.14 wording would have
done and why that item was re-planned first.

The new fact is about CLAIMS. Rule 1 already says to prefer a derived
fact over a restated one, and to verify the binding by sabotage. It does
not warn that an author may believe they derived a fact when they only
MOVED the restatement -- and such an author will sabotage the old site,
watch it go red, and record the class as closed. Measured on one guard in
windows-platform-probes three times in succession (strings, a
hand-written ALL, generation), each fix relocating the census somewhere
harder to see while its commit message claimed the class was closed, and
each caught by a review rather than by its author.

The second paragraph points at the mechanism rather than describing it:
the manifest, run-sabotage.ps1, README-sabotage.md for the format and for
why a manifest with no control can only tell you the tests are sensitive.
It also states that the harness is the authority on patch-site
uniqueness, because re-implementing that check beside it is the same
defect -- as the previous commit measured.

Completed item: M2.14.2: Add to CONTRACT INTEGRITY rule 1 the one thing this branch learned that it does NOT already say, and a pointer to the mechanism
Completed item: M2.14: Make the two authoring rules this branch earned actually bite

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
M3.9. The oracle's question is "could a consumer read this row", and a
consumer uses a JSON parser. Anything hand-written here is a second
opinion about what JSON is, and a second opinion is a thing that can
disagree -- so malformation now calls serde_json and the scanner is gone.

Measured, and the measurement is why this happened at all. The
hand-written check had already been through a review, which strengthened
it after finding it accepted {"a":1,}. A generated test -- 1807
single-character corruptions of a real row, judged against serde_json --
then found 159 MORE disagreements, every single one a false accept: 129
stray backslashes forming invalid escapes, 10 missing ':', 13 ',' where a
':' belonged, 3 the reverse, 3 missing values, 1 string following a
number. The review had found one instance of a class with 160 members.
Closing the last ~26 required tracking whether an object expects a name
or a value next, which is a JSON parser; so the choice was to write one
or to depend on one.

The agreement test was deleted in the same commit, deliberately. With the
parse delegated it would compare serde_json against serde_json -- green
by construction, and exactly the tautology this milestone keeps deleting.
What replaced it asks a question that is still open: not whether the
verdict is right, but whether it REACHES the caller, which is a property
of `check` that no parser guarantees. It found a real boundary while
being written: 8 corruptions destroy the leading brace, and those are
Missing rather than Malformed -- not a row at all, which for a survey
asking "did this host report a row" is the right answer and a different
one. Both branches are asserted.

Three tests stopped asserting the defect's wording. The message is
serde_json's now, so this crate does not own it; pinning it would let a
dependency's patch release redden tests about unclosed delimiters, which
would be a false finding about this crate.

A parse does NOT subsume RepeatedKey, which is why that check stays hand
-written: serde_json accepts a duplicated key and silently keeps the
last, precisely the malformation that survives a consumer's parse and
changes what it reads.

BREAKING CHANGE: report_oracle is now gated on cfg(any(test, feature =
"oracle-in-renderer")), and RowDefect::Malformed carries a String rather
than a &'static str. Every caller was already behind that gate; stating
it is what keeps the parser out of a shipping probe. Verified by
inspecting the binaries, per the precedent in that feature's own comment:
the default probe-topology.exe contains no serde_json, no oracle panic
string and no parser message, while the --all-features one contains all
three.

Swept the class rather than the reported site: fixed the module's stale
claim that the key-set check was deferred, and the checklist's claim that
the delimiter stack was the answer. Sabotage manifest re-swept, 7 of 7
still as declared. cargo doc verified in BOTH feature shapes -- the
no-features build caught an intra-doc link the gate had broken.

Completed item: M3.9: Decide the row's well-formedness by a real parse, and delete the hand-written one

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
M3.10. M3.9 removed one of six scanners in the oracle; this removes the
rest. The module hand-writes no string walking at all now -- every
byte-level decision about quotes, escapes and delimiters is serde_json's.

Two of the four were provably unsafe on an argument nothing enforced.
list_codes found "code":" and took the next quote as the end; list_span_end
counted brackets with no notion of being inside a string. Both were safe
only because every code is a &'static str from an enum and no caller text
reaches a diagnostic list -- true, load-bearing, and guarded by no test.
keys had already proved the class reachable: it made assert_corresponds
panic from inside report_unmeasured on a quoted discovery_error. Parsing
makes the argument unnecessary rather than merely correct, which is the
difference between a property and a hope.

keys needed a MapAccess visitor rather than a parsed map, and the reason
is a contract. It must return the row's names in ORDER and WITH
DUPLICATES, and serde_json::Map sorts while silently keeping the last of
a repeated key -- which would delete the evidence for
RowDefect::RepeatedKey, the one malformation that survives a consumer's
parse. The visitor reads each name as the parser reads it, so both
properties survive while every scanning decision stays serde_json's. That
reasoning is now a sabotage entry rather than a comment: replacing the
visitor with the obvious Map one-liner is caught.

list_span_end was deleted, not moved. Its only caller was a sabotage
doing text surgery on a list; that sabotage now parses, empties the lists
and re-renders. It is the third implementation, after one that split on
commas -- which sliced entries in half once they became objects -- and one
that used this helper. A sabotage that hand-parses is a sabotage that can
quietly stop sabotaging while still passing, leaving the rule it guards
unguarded.

The stale manifest entry is itself the evidence. After the change the
sweep reported MANIFEST STALE: pattern found 0 times for the
escape-awareness entry, because the code that could hold that defect is
gone. Replaced with the parsed-map entry; 7 of 7 behave as declared.

serde joins serde_json as an optional dependency behind the same
oracle-in-renderer gate. Default build re-verified by binary inspection:
neither appears on a normal dependency edge and probe-topology.exe
carries no parser string. cargo doc checked in both feature shapes.

Completed item: M3.10: Delete the last hand-written string scanners in the oracle

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All ten M3 items are complete, so the group migrates to
COMPLETED-CHECKLIST.md and the active checklist is left holding only M4
and M5. Both PLANS.md entries said "M3.1 has landed", written when M3.1
was the only item; ten had landed since, including two that reversed
decisions the same paragraph described.

The re-scoping notes did NOT go to the archive. M4's preamble said "M3's
preamble says which M3 item gates each of them", and the notes it meant
-- how M3.2 re-scoped M2.4, how M3.1 and M3.3 gated M2.5, what evidence
M3.4 took away from M2.15, how M3.5 re-scoped M2.17 -- are instructions
for work that is still open. A pending instruction does not belong in an
append-only file nobody may edit to correct it, so they moved into M4's
preamble and M3's record carries a pointer rather than a second copy.

Also corrected three statements the closure falsified: M4's heading and
preamble spoke of M3 in the present tense, M5's said its items could be
pulled ahead of "M3 or M4", and M2.14.1's body still said this crate
carries no sabotage manifest -- true when written, false since the item
it describes was completed.

End-of-milestone gate, all clean: cargo check --all-targets on the
DEFAULT workspace (not --workspace, so the deliberately excluded members
stay excluded) in debug and release, zero compiler diagnostics in either;
the in-scope crate's tests unfiltered so doctests run, 213 passed 0
failed, with Doc-tests reporting 0 -- confirmed real rather than a
harness quirk, the crate has no doc code blocks at all; encoding check
642 files clean; both markdown files verified 7-bit ASCII and free of
dangling anchors. git fetch reports origin/main at 3f31e92, already
contained in HEAD, so there was nothing to integrate and no
ON-GIT-MERGE-OR-REBASE trigger.

Not pushed, at the engineer's instruction.

Completed item: M3 (milestone closure): archive the completed group, update both PLANS.md entries, and relocate the still-live re-scoping notes into M4

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two of the dated formats already required one -- `## Resolved <... +-hh:mm>`
and the completed-item stamp -- while `## Moved` did not. Worth noting that
the correct form was present and then drifted: the first heading in this
workspace's COMPLETED-CHECKLIST.md is a full `## Moved 2026-09-09 19:00:17
-04:00`, and the four entries after it are bare dates.

Framed as a presentation concern rather than a correctness one, because
that is what it is. A bare local date is not wrong -- the event happened
when it happened -- it is just ambiguous in a way a few characters remove.
An offset does not stop a machine with a misconfigured zone from writing a
misleading date; it makes that date convertible afterwards, which is the
whole of the benefit.

The worked example is this session. A laptop reporting -04:00 while its
owner sat in -07:00 ran three hours fast, so timestamps taken late in the
evening carried the next day's date. Every affected commit stayed
unambiguous because git stores the instant with its offset, so
2026-09-13T01:14:28-04:00 is exactly 2026-09-12 22:14 -07:00. One bare date
in a checklist was the only thing that had to be re-derived from elsewhere,
and it is corrected here.

The rule explicitly does NOT ask anyone to go back and repair bare dates
already written, or to rewrite history to relabel an offset. Instants are
correct either way, and rewriting changes every hash -- on this branch two
tracked files cite commit hashes, one of them a split's mandatory
`Split from ... at <hash>` provenance line, and both would dangle. An
archive heading upgraded in the course of writing this was reverted for the
same reason: COMPLETED-CHECKLIST.md is append-only, and a heading that is
merely imprecise is not grounds to edit it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… falsified

A whole-branch review found no defects in the code and two clusters of
stale claims, both written early on this branch and falsified by its own
later commits. This is the drift class the surrounding prose describes,
landing in the file that is least allowed to carry it.

Tier 1 DESIGN-NOTES, section D-encoded-row-is-the-contract:

- It said "Nothing here enforces that rule yet" and pointed at CHECKLIST.md
  for the queued M3.5. M3.5 landed on this branch, so the rule IS enforced
  -- by every_state_that_blocks_agreement_reaches_the_row and the shared
  publication_holds predicate -- and CHECKLIST.md no longer contains the
  item, which is archived. This was the costly one: it instructed the next
  reader not to assume the instruments cover the rule, when they do.
- It said the row "is built today" by interpolating positionally through a
  concat! template. That template was deleted three commits later; the row
  goes through Row::with and src/row.rs is the typed writer the sentence
  described as hypothetical. The only concat! left in topology_report.rs is
  inside a comment about the old design, verified by grep before saying so.
- It counted report_oracle.rs's functions in the present tense. That file
  no longer extracts text at all. Restated as what the design COST, with no
  count of the current file -- a count of a live file is a census, and this
  branch has already corrected several.

Cargo.toml: the dev-dependency comment asserted the opposite of what Cargo
does. It claimed cfg(test) builds compile report_oracle WITHOUT
oracle-in-renderer. They do not: the self dev-dependency is an edge from
the package to itself, so under resolver 2 the feature unifies onto the
package in any build that includes dev-dependencies. Measured with a
compile_error! probe in both directions -- cargo check --tests succeeds
under not(feature) and fails under feature, while a plain --lib build has
it off. Consequently the matching serde dev-dependency was dead weight and
is removed; all 213 tests pass without it.

Also repointed src/topology/invariant.rs at COMPLETED-CHECKLIST.md for the
M3.2 sabotage evidence, which the archive commit had left pointing at a
file that no longer holds the item, and named the sabotage.json entry that
now re-runs that evidence instead of asserting it.

Two claims written while fixing this were themselves wrong and were caught
by checking rather than asserting: the replacement text said report_oracle
"is now five functions" (it is six, so the count was dropped rather than
corrected), and the concat! claim needed the comment-versus-code
distinction above.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…es it

A whole-branch review found the module header's central claim false for
two push sites. It says "a push site deleted from `cross_check` leaves the
state visible here and fires the rule; that is the whole design" -- an
unqualified claim, and NUMA was not covered by any rule, so deleting
either NUMA push fired nothing here.

The exclusion had a rationale, and the rationale was half right.
`GetNumaHighestNodeNumber` reports the largest node NUMBER rather than a
count, so there is no enumerated quantity to hold it to: nodes 0 and 2 are
a valid sparse topology, and comparing it against `numa_domains` would
manufacture a violation on hardware reporting itself correctly. That rules
out ONE comparison. It does not rule out the comparison `cross_check`
actually makes, which is highest-against-highest, and excluding NUMA on
the strength of it left the claim overstated rather than the code wrong.

Measured, and the measurement is why this is a `fix` and not a `docs`:
deleting the NUMA disagreement push was CAUGHT -- by two direct
`cross_check` unit tests, not by the invariant layer. So this was never a
hole in the suite. It was a hole in the layer whose whole stated purpose
is to catch exactly that deletion, which is worse in one specific way: a
reader who trusts the header would believe the layer covers a push site it
does not.

Closed by adding the rule rather than by narrowing the claim. `agree` is
reachable only through both NUMA branches declining to fire, so beside
`agree` the counter must have been readable and equal --
`AgreedWithoutComparingCounter` reuses the existing variant for the
unreadable case, and a new `AgreedDespiteNumaMismatch` carries the
optional parse for the mismatch, because folding an `Option<u32>` into the
count-shaped variant would have meant inventing a `usize` for an absent
parse.

Sabotage-verified after the change: the same deletion now reddens
`every_numa_branch_in_the_real_cross_check_is_one_this_module_forbids`,
which pairs each branch against the real `cross_check` the way the other
states were already paired. The sparse-topology test is kept and its
comment now says why the two rules differ, since it is the case that
distinguishes them.

Also narrowed the sabotage control's `why`, which claimed "no test may
read the prose" and declared any test catching a prose reword to be the
defect. False: about 35 tests assert report text with `contains`, because
the human report is a deliverable worth covering. The real rule is that no
test may derive a MACHINE-CONTRACT requirement from the wording. As
written it would have told a future reader to delete legitimate coverage.

Manifest re-swept, 7 of 7 as declared. 216 tests pass on x86_64 and i686.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…they imply

First mutation sweep of the two modules M3 created. row.rs came back
clean on its first run -- 25 tested, 19 caught, 6 unviable, no survivors
-- which review could not have established. topology/invariant.rs gave up
three survivors, of two different kinds.

**The two that were a real gap: `online_processors > 0` relaxed to `>= 0`
in blocking_states.** The guard says a machine WITH processors and no
packages is a finding; relaxing it accuses a topology that reported
nothing of hiding packages it never claimed.

The condition exists twice on purpose. cross_check has its own copy, and
blocking_states must recompute rather than read cross_check's output, or
it restates verdict() and goes blind to a deleted push site -- the whole
reason the module exists. Independence is the design; AGREEMENT is the
property, and the property was untested. The test that names this
boundary, a_topology_with_no_processors_at_all_is_not_accused_of_hiding_packages,
asserts on cross_check, so it covered one copy and left the other open.
Five review rounds across four models did not find this; the sweep did,
because a reviewer reasons about what code claims and a sweep asks what
nothing notices.

Closed by holding the two copies against each other over a corpus that
spans the boundary, rather than by pinning one case: a guard whose
condition drifts on either side is now caught wherever it drifts. A
companion test asserts the corpus reaches BOTH answers, since a
correspondence over shapes that all land on one side passes vacuously.

**The third is equivalent and no test can kill it: `assert_holds` ->
`()`.** It derives the verdict from observation.cross_check(), and
check()'s rules hold for every such pair by construction -- they are
reachable by code change, not by data, which is exactly why check() takes
the verdict as a PARAMETER so a test can supply what a broken cross_check
would give. assert_holds has no such seam, so nothing distinguishes it
from (). The argument is now recorded at the function rather than left
for the next sweep to rediscover, matching the assert_corresponds
precedent from PR #88.

Deliberately NOT added to sabotage.json: a `survives` entry means "this
change is not a defect", and removing an assertion IS a defect -- one that
happens to be undetectable. Labelling it `survives` would assert the
opposite of the truth.

The processor guard IS added to the manifest, so the pairing is re-run in
two minutes rather than rediscovered in a three-minute sweep. 8 of 8
behave as declared. Re-swept after the fix: 23 caught, 1 missed, and the
one is the equivalent mutant above.

Sweep results recorded in DESIGN-RATIONALE.md, which claimed three sweeps
and now states five.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A whole-branch review found the row's own payloads unchecked, and a sweep
of the module put a number on it: 26 mutants, 9 caught, 12 MISSED. 46%.

This is the field-labelling defect row.rs exists to make unrepresentable,
reappearing one level down. row.rs pairs a name with its value so position
cannot mislabel them, and MEASURED_ROW_KEYS closes the top-level key set.
Then published() hand-pairs names with values INSIDE each entry, and
nothing was watching.

What that left open, measured rather than reasoned:

- Rewriting the count helper to `*value * 7 + 1` -- every count in every
  parse_incomplete entry wrong -- left 218 tests passing. Reproduced
  before touching anything.
- NotCompared::code could be replaced wholesale with "" or "xyzzy". Its
  own doc says "Changing one of these is a breaking change to the NDJSON
  row"; not one of the six was pinned anywhere.
- Every arm of published_anomaly was deletable, losing source labelling
  and every payload field.
- Two arms of anomaly_code were deletable, so a real buffer overrun would
  publish as `unclassified` -- whose documented meaning is "this probe's
  vocabulary is older than the crate". A survey would mis-attribute it
  rather than see it.

The tests that LOOKED like they covered this could not. They built their
expectation from code() and compared it against a row the writer had built
from code(), so both sides moved together -- the tautology class this
branch deletes elsewhere, in the one place it mattered most.

Closed with goldens, written as literals on purpose. A predicate over
values is defined once and asked, never restated; a code and a field name
are not predicates but a SCHEMA, and a schema is not derivable from the
thing that emits it. Writing it twice is how a golden works. Completeness
is compiler-checked where the enum belongs to this crate: the expectation
is an exhaustive match, so a variant added without a golden does not
compile. AnomalyKind and Source are #[non_exhaustive] upstream, so those
use explicit instances plus a direct assertion that a named kind does NOT
fall through to the catch-all.

Sabotage-verified: the count rewrite that left 218 green now reddens.
Re-swept: 12 missed becomes 2.

The two that remain are both Display impls -- the PROSE rendering, which
under d-encoded-row-is-the-contract is a review obligation rather than a
machine-checked one. Left open deliberately and recorded as such, not
closed in passing: whether prose deserves machine coverage is a decision
about where that line sits.

Also corrected DESIGN-RATIONALE.md, which said five sweeps covering "the
two modules M3 created". M3 created THREE, and the unswept one was the
largest at 629 lines and the only one with survivors. My own claim from
commit 6f57dd5, wrong within the hour -- the same class as b54c3a0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nothing

The last two mutation survivors were both `Display` impls. Blanking
either left the suite green, and a reader would have got `     - ` with
nothing after the dash.

Both obvious answers were wrong. Pinning the sentences would make the
prose machine-checked, which d-encoded-row-is-the-contract deliberately
does not do -- the row is the machine contract and the prose is a review
obligation. Leaving them ships a blank line.

The engineer named a third: a blank is perhaps wrong, perhaps it should
be called out. That is better than either, because it separates two
things the survivors had conflated. **A diagnostic's WORDING is a review
obligation; its PRESENCE is not.** Presence is structural -- the renderer
knows it holds an entry to print -- so it can be machine-checked without
any sentence being pinned.

So the renderer routes every diagnostic through `described`, which
substitutes an explicit BUG IN THIS PROBE line for a rendering that is
empty or blank, and a test asserts no diagnostic renders as that line.
That pins THAT each entry describes itself without pinning WHAT it says.

A blank was the worst available answer on its own terms, separately from
the sweep: it is indistinguishable from a rendering bug, from a finding
with genuinely nothing to say, and from a stray newline, so a reader
cannot tell whether the probe found something it failed to describe.

Both improvements fall out of the one branch. The reader gets a stated
defect instead of a blank, and the mutants become catchable, because
blanking a Display now produces the callout the test forbids.

Verified: diagnostic.rs swept to ZERO survivors, from 12 two commits ago
and 2 before this one -- including the two mutants `described` itself
introduced, so the fix carries its own coverage. Whitespace is treated as
blank, since a reader cannot tell it from emptiness on the page, and a
test pins both.

The sabotage manifest's prose control STILL survives, which is the check
that matters here: `described` did not quietly move the line by making
wording machine-checked. 8 of 8 behave as declared.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 14, 2026 03:12
Copilot AI review requested due to automatic review settings September 14, 2026 06:21
…nderer, and unbreak the default doc build

Three findings from the review of 40ea4f3, two of them mine from that commit.

**`published_codes` discarded every payload field**, so the only end-to-end
renderer test would have stayed green if `topology_report` dropped or reshaped
`parsed`, `counter`, `level` or an anomaly's metadata. The per-variant tests
cover `published()` in isolation; nothing covered it THROUGH the renderer.
`the_row_carries_each_diagnostic_entry_whole_and_not_only_its_code` now compares
each rendered entry, for all four diagnostic lists, across every corpus shape.

The expectation is derived from `published()` rather than written out, so it
cannot drift from the publisher; what it pins is that the renderer carries that
value through unchanged.

**The first sabotage of it was wrong, and the correction is the useful part.**
Deleting `offset` from `published_anomaly` left the new test green -- correctly,
because both sides derive from that function, so sabotaging the PUBLISHER moves
them together. The defect the reviewer described is in the RENDERER, and
sabotaging there -- mapping the anomalies back to bare codes, the superseded
M3.1 form -- reddens it along with four neighbours. A test that derives its
expectation can only be sabotage-verified at the layer it actually constrains.

**The `RowDefect::RepeatedKey` intra-doc link broke `cargo doc`.** `row` is
always built, `report_oracle` is compiled only under `cfg(any(test, feature =
"oracle-in-renderer"))`, so the link cannot resolve in a default documentation
build and emitted a broken-intra-doc-link warning. Demoted to plain code text,
with the reason recorded beside it. Confirmed by running `cargo doc -p
windows-platform-probes --lib`, which is now clean.

That is the same feature-gating trap as b68a124 in a third guise -- module,
statement, and now doc link. Everything local compiles with the feature ON
because of this crate's dev-dependency on itself, so each variant has to be
caught by a build that does not.

**The design-session key list** read as a current-schema list missing
`disagreements`, which was a fair reading of how d523f2b introduced it: a
sentence pointing at `MEASURED_ROW_KEYS` as the authority, followed by a colon
and the historical eighteen. The framing now says plainly that the list is the
eighteen as they stood at that session and is not reproduced as current.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

One critical publication invariant issue and three moderate row-contract issues remain, along with a checklist nit.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (4)

Previously missed (1) — in code that hasn't changed since the last review.

crates/windows-platform-probes/src/row.rs:241

  • This intra-doc link points at report_oracle, but that module is compiled only under test or oracle-in-renderer; a normal/default rustdoc build therefore has no crate::report_oracle::RowDefect to resolve and reports a broken link. Keep the type name as an unlinked code reference, or make the referenced API available in default documentation; the analogous isolated default-doc jobs in .github/workflows/ci.yml show this configuration is intentionally checked.

crates/windows-platform-probes/CHECKLIST.md:13

  • The milestone preamble says every carried item has its own post-M3 re-scoping note, but M2.5 still carries the old instruction to put this correspondence in the deleted M2.1 oracle (rather than in the surviving observation/renderer design). Re-scope that item before marking the milestone ready; otherwise an executor following this checklist is sent to a component M3 explicitly removed.
These were written under M2 and were blocked on M3, which is **now complete and archived** in
[COMPLETED-CHECKLIST.md](COMPLETED-CHECKLIST.md). They are unblocked, and each was RE-SCOPED rather
than merely delayed -- so each item below carries its own re-scoping note, in the item, where
somebody executing the list will actually meet it.

crates/windows-platform-probes/src/row.rs:171

  • Value::Object is public and documents an ordered set of members, but unlike Row::with it does not reject duplicate names. A caller can therefore construct a nested object with the same key twice; the writer emits ambiguous JSON, while the oracle's duplicate-key check only examines top-level members. Reject repeated names in this loop so every object in the machine contract has the same uniqueness guarantee.
                for (at, (name, value)) in members.iter().enumerate() {
                    if at > 0 {
                        out.push(',');
                    }
                    write_escaped(out, name);

crates/windows-platform-probes/src/row.rs:82

  • These shapes validate only the outer list and, for diagnostics, the presence of a string code; they do not validate the member fields that are part of the row contract. Consequently, dropping domains from a cache object or dropping count/level/other payloads from a diagnostic object would still pass the renderer's shape assertion, while the standalone publisher goldens do not exercise the renderer boundary. Add recursive member schemas or an independent rendered-row check for the exact payload fields before treating this as the complete machine contract.
    /// by, so an entry without one is unmineable even though it is valid JSON.
    ListOfCoded,
    /// An object whose every member is a number.
  • Files reviewed: 23/25 changed files
  • Comments generated: 1
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 14, 2026 06:33
@MikeGrier

Copy link
Copy Markdown
Owner Author

Round 9 disposition: the five suppressed comments

Continuing the ledger. All five addressed -- three were already fixed in b68a124 before this review landed, two were new and are fixed in 399cc39. The two inline comments are answered and resolved in their threads.

Already fixed when the review arrived

Both topology_report.rs findings (the ungated second assertion at :985, and the mangled comment at :983) are the defects I found myself ten minutes after pushing 40ea4f3, when CI's cargo run --bin failed with E0433. Fixed in b68a124. Independent confirmation of the diagnosis, which is worth something.

New, and both mine

The RowDefect::RepeatedKey intra-doc link broke the default doc build. row is always built; report_oracle is compiled only under cfg(any(test, feature = "oracle-in-renderer")). Verified rather than assumed -- cargo doc -p windows-platform-probes --lib emitted a broken-intra-doc-link warning. Demoted to plain code text with the reason recorded beside it; the doc build is now clean.

That is the same feature-gating trap in a third guise: module, statement, and now doc link. Everything local compiles with the feature ON because this crate dev-depends on itself, so each variant has to be caught by a build that does not.

published_codes discarded every payload field. You are right that the only end-to-end renderer test would have stayed green if topology_report dropped or reshaped parsed, counter, level or anomaly metadata. the_row_carries_each_diagnostic_entry_whole_and_not_only_its_code now compares each rendered entry, for all four diagnostic lists, across every corpus shape -- with the expectation derived from published() so it cannot drift from the publisher.

My first sabotage of it was wrong, and that is the useful part. Deleting offset from published_anomaly left the new test green -- correctly, because both sides derive from that function, so sabotaging the publisher moves them together. The defect you described lives in the renderer; sabotaging there (mapping anomalies back to bare codes, the superseded M3.1 form) reddens it along with four neighbours.

The general lesson, now in the commit message: a test that derives its expectation can only be sabotage-verified at the layer it actually constrains. Picking the wrong layer produces a false all-clear that looks exactly like a real one.

Design-session key list

Fair reading, and my fault. d523f2b introduced a sentence pointing at MEASURED_ROW_KEYS as the authority, followed by a colon and the historical eighteen -- which reads as a current-schema list missing disagreements. The framing now says plainly that the list is the eighteen as they stood at that session and is not reproduced as current.

Unrelated: a CI flake, diagnosed not patched

build + test failed on b68a124 with 100 failures in windows-namespace-request-sys, all assertion failed: !was_still_open(raw). That crate is untouched by this branch; all 236 of its tests pass locally; and a re-run of the identical commit passed. Recorded here rather than worked around -- it looks like handle-value recycling across concurrently running tests, which this repository already documents as a hazard of running tests as threads in one process.

… and a row key

A review read `codes_for(State::EnumerationAnomalies)` as naming the row KEY
`enumeration_anomalies`, concluded that `publication_holds` could not find it
because `DIAGNOSTIC_LISTS` deliberately excludes that list, and reported the
assertion as failing for the `anomalies` corpus shape.

It does not fail. The string is a condition CODE carried inside
`parse_incomplete`: `cross_check` pushes `ParseIncomplete::EnumerationAnomalies`
when the observation records any, and that variant's code is this same word. So
`publication_holds` finds it while scanning the three diagnostic lists, and
`every_state_that_blocks_agreement_reaches_the_row` exercises exactly that shape
-- all 11 tests in the target are green, before and after this commit.

The collision is real even though the conclusion was not: one word names both a
row key and a condition code, and a careful reader took it for the wrong one.
Noted at the arm, since the next reader has the same chance of being misled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Nested duplicate-key enforcement and complete nested cache schema validation remain unresolved.

Review details

Suppressed comments (2)

crates/windows-platform-probes/src/row.rs:107

  • Value::Object is public and is documented as a set, but it accepts duplicate names and write emits both of them. Row::with only rejects duplicate top-level members; a caller can still render a nested object such as {"code":"a","code":"b"}, which JSON parsers accept while silently retaining one value, so the duplicate-key integrity guarantee does not cover the public value API. Enforce uniqueness for every object (or hide this construction behind a checked constructor) before treating the row as unambiguous.
    /// An ordered list.
    List(Vec<Value>),
    /// An ordered set of named members.
    Object(Vec<(&'static str, Value)>),

crates/windows-platform-probes/src/topology_report.rs:84

  • ListOfObjects only checks that each caches element is an object, so [{}] or [{"level":"L1","domains":[]}] satisfies MEASURED_ROW_SHAPES even though the renderer's cache contract publishes numeric level and domains members (topology_report.rs:819-822). There is no independent topology-report assertion for those nested fields, so a regression can change the mined cache payload while the row-shape oracle stays green; add a nested-object schema or a golden that rejects missing/wrongly typed members.
    "caches" => Shape::ListOfObjects,
  • Files reviewed: 23/25 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 14, 2026 06:43
…not just the first

Two gaps a review found in last round's work, both measured before being fixed
and both the same shape of defect: a guarantee stated for the ARTIFACT and
enforced only for its outermost level.

**Duplicate keys were rejected at the top level only.** `Row::with` refused a
repeat among the row's own members, so a nested entry could still render
`{"code":"a","code":"b"}` -- measured, exactly that string -- which
`serde_json` and `JSON.parse` both accept while silently keeping one value. The
oracle could not report it either, because `keys` reads top-level names by
design. `Row::with` now walks the whole value tree.

Uniqueness is per OBJECT, not across the row: every diagnostic entry carries
its own `code`, and a rule forbidding that would reject every real report. A
sibling-objects control pins that, so the check cannot be tightened into
nonsense later.

**`caches` promised only "a list of objects", so `[{}]` satisfied it.** The
renderer publishes numeric `level` and `domains`; nothing checked either.
Measured: an empty cache object produced zero violations. (`[{}]` is also,
exactly, the bogus shape a design session claimed the row emitted and which was
corrected earlier on this branch. It was never a real rendering -- but it was
reachable through the checker.)

`Shape::ListOfObjectsWith(&[(name, shape)])` replaces both `ListOfObjects` and
`ListOfCoded`, which generalises rather than adding a special case: the coded
lists become `ListOfObjectsWith(CODED)` and `caches` names its two numeric
members. Extra members stay legal -- what a schema owes a consumer is that the
fields it PROMISES are present and typed, and forbidding additions would make
every new field a breaking change to the checker rather than to the contract.

The checker is now recursive and reports WHERE rather than only THAT:
`caches[0].level should be Number but is "2"` instead of one sentence about the
whole list.

Sabotage-verified, each against its own claim:

  - A nested duplicate now panics in the writer, naming the member; the
    sibling control still renders both `code`s.
  - Publishing `cache.level` through `.to_string()` fails 19 library tests
    naming `caches[0].level`, against 0 before.

The `caches` test takes its schema FROM `MEASURED_ROW_SHAPES` by filtering for
the key, rather than restating the shape beside it. Written out, it would have
pinned a shape of its own and passed while the declared schema said something
else -- the copy checking the copy, which is the defect this branch keeps
finding. The first draft did exactly that, with a doc comment claiming it was
derived.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@MikeGrier

Copy link
Copy Markdown
Owner Author

Round 10 disposition: both suppressed comments

Both fixed in 0c4aced. Both were genuine gaps in last round's work, and both are the same shape of defect: a guarantee stated for the artifact and enforced only for its outermost level.

Value::Object accepted duplicate names

Right. Row::with refused a repeat among the row's own members; a nested entry could still render it. Measured before fixing -- the literal output was:

{"reason":"x","parse_incomplete":[{"code":"a","code":"b"}]}

The oracle could not report it either, since keys reads top-level names by design. So the duplicate-key guarantee I added last round covered one level of the thing it claimed to cover.

Row::with now walks the whole value tree. Uniqueness is per object, not across the row -- every diagnostic entry carries its own code, and a rule forbidding that would reject every real report -- so there is a sibling-objects control pinning that the check cannot be tightened into nonsense later.

I took the "enforce for every object" option rather than hiding construction behind a checked constructor: Value::Object stays a plain public variant, and every path into a row goes through with.

caches promised only "a list of objects"

Also right, and measured: an empty cache object produced zero violations.

Worth noting that [{}] is exactly the bogus shape a design session claimed the row emitted, which I corrected earlier on this branch. It was never a real rendering -- but it was reachable through the checker, which is a better argument for your finding than anything I would have written.

Rather than special-case caches, Shape::ListOfObjectsWith(&[(name, shape)]) replaces both ListOfObjects and ListOfCoded: the diagnostic lists become ListOfObjectsWith(CODED), and caches names its two numeric members. Extra members stay legal, deliberately -- a schema owes a consumer that the fields it promises are present and typed; forbidding additions would make every new field a breaking change to the checker rather than to the contract.

The checker is recursive now and reports where, not just that:

`caches[0].level` should be Number but is `"2"`

Verification

sabotage before after
nested duplicate key rendered silently writer panics, naming the member
cache.level via .to_string() 0 failures 19 library tests, naming caches[0].level

One note against myself: the caches test now takes its schema from MEASURED_ROW_SHAPES by filtering for the key. My first draft hand-wrote the shape while its doc comment claimed it was derived -- the copy checking the copy, which is the exact defect this branch keeps finding. Caught it on re-reading before commit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved moderate findings remain in nested schema validation and IoRing handover timing coverage.

Review details

Suppressed comments (6)

Previously missed (1) — in code that hasn't changed since the last review.

crates/windows-ioring-sys/tests/handover.rs:540

  • attached.elapsed() is evaluated before drain_to_empty, so to_polled is actually attach-to-before-poll (nearly zero), while the failure text claims attach-to-polled. This removes the timing evidence the new escalation diagnostics are meant to provide; capture attached.elapsed() immediately after the non-blocking drain and store that value.

crates/windows-ioring-sys/tests/handover.rs:121

  • This ordinary test can issue up to 4 * (8 + 16 + 32 + 64) unbuffered 1 MiB reads before failing, and it hard-fails when the host completes every read before completion_event() attaches. That outcome is a device/scheduling property, not evidence that handover strands anything, so a fast legitimate device can make the normal suite slow and red. Move this timing-dependent reachability probe to an explicitly run/ignored test or make the fixture deterministically hold an I/O in flight.
const DIRECT_WIDTHS: [usize; 4] = [8, 16, 32, 64];

crates/windows-platform-probes/COMPLETED-CHECKLIST.md:500

  • This newly added archive heading uses only a bare date, but the same PR adds the repository rule that newly written dates must include a time and UTC offset. Please record the actual completion timestamp here with its offset so this archive entry follows the rule it introduces.
## Moved 2026-09-12 -- M2 completes: the report oracle, its fact set and its shape corpus

crates/windows-platform-probes/COMPLETED-CHECKLIST.md:527

  • This newly added M3 archive heading also omits the time and UTC offset required by the timestamp rule added in this PR. Unlike the M2 entry, there is no nearby timestamp that can be reused; please record the actual completion timestamp here rather than leaving a bare local date.
## Moved 2026-09-12 -- M3: the encoded row became the contract, and the prose stopped being checked

crates/windows-platform-probes/src/row.rs:81

  • These shapes validate only the outer container and, for diagnostics, that a string code exists. The renderer-bound schema therefore accepts {} or {"level":"1"} as a cache entry and accepts a diagnostic object with all variant payloads omitted; ObjectOfNumbers likewise cannot detect missing or extra policy fields. The new row contract does not enforce the nested data the renderer promises to publish; add nested schemas or explicitly document that those members are unconstrained.
    ///
    /// **Recursive, because "a list of objects" was not a contract.** That is
    /// what this replaced, and `[{}]` satisfied it -- so `caches` could stop
    /// publishing `level` and `domains` with the shape oracle green, and a
    /// diagnostic entry could lose the `code` a survey groups by. Reported by a

crates/windows-platform-probes/src/topology_report.rs:84

  • Shape::ListOfObjects only validates the outer array/object shell. The renderer treats each cache object as {"level": number, "domains": number} (lines 819-822), but this schema still passes if either member is deleted or changed to a string. The current cache tests only assert the writer's sample output, so a renderer regression here can reach the row unchecked; add a nested cache-entry shape and exercise it through the renderer.
    "reason" => Shape::Text,
  • Files reviewed: 23/25 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 14, 2026 06:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A moderate compile-blocking issue and two documentation nits remain unresolved.

Review details

Suppressed comments (3)

crates/windows-platform-probes/DESIGN-NOTES.md:1033

  • This retired decision is explicitly superseded by the encoded-row decision, but its status is only stated below the preserved anchors as “Moved to Tier 2.” Put a **Superseded by [...]** marker directly beneath the heading (before the anchors or other prose) so readers cannot mistake this historical section for a current decision.
**Moved to Tier 2: [DESIGN-RATIONALE.md](DESIGN-RATIONALE.md).** The anchors

crates/windows-platform-probes/DESIGN-NOTES.md:1177

  • This inline-code file reference is not clickable, unlike the linked reference to the same file three lines later. Use a relative Markdown link here as well so readers can open the historical source directly from the design note.
Counted in `src/report_oracle.rs` **as it stood before this decision**: of 38

crates/windows-platform-probes/src/topology/invariant.rs:310

  • Observation::coherence is a non-Copy Coherence value, so matching observation.coherence through &Observation attempts to move it out of a borrowed struct and fails to compile. Match by reference here, as CrossCheck already does for self.coherence.
    match observation.coherence {
  • Files reviewed: 23/25 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

…ts it

Two documentation findings, both correct against the repository's own rules,
and one rejection.

**The retired correspondence-oracle decision stated its supersedence twelve
lines into the body.** The rule is explicit that the marker goes adjacent to
the title "even when the fuller explanation already appears later in the
decision's body", precisely so a reader cannot take a superseded section for a
current one by reading the top of it. Added beneath the anchors, matching the
shape the buffered-report decision already uses, and the fuller explanation
lower down is left as it was.

Swept rather than fixing the reported site alone: this file has exactly two
superseded decisions and both now carry an adjacent marker.

**An inline-code file reference was not clickable**, three lines above a linked
reference to the same file. Linked. Swept: no unlinked `src/...` references
remain in the file.

**Rejected: `match observation.coherence` "fails to compile".** It does not,
and this is the third round reporting this shape -- twice against
`diagnostic.rs`, now against `invariant.rs`. Matching a place expression behind
a shared reference is a move only when a PATTERN BINDING moves a non-`Copy`
value; all three arms here are unit-like or `{ .. }` and bind nothing.
`cargo check --all-targets` is clean across the workspace and has been on every
commit these lines have existed.

Left as it is rather than adding a no-op `&` to satisfy the claim -- but a note
now sits at the match, because three rounds spent on one false positive is
itself evidence the code should say why it is correct.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 14, 2026 07:55
@MikeGrier

Copy link
Copy Markdown
Owner Author

Round 11 disposition: the three suppressed comments

Two fixed in c1927a2, one rejected with evidence.

Supersedence marker -- fixed

Correct, and against this repository's own rule, which says the marker goes adjacent to the title "even when the fuller explanation already appears later in the decision's body" -- precisely so a reader cannot take a superseded section for a current one by reading the top of it. The explanation was twelve lines down.

Added beneath the anchors, matching the shape the buffered-report decision already uses rather than introducing a second convention. Swept: this file has exactly two superseded decisions, and both now carry an adjacent marker. All three anchors verified still present.

Unlinked file reference -- fixed

Correct, and slightly embarrassing: it sat three lines above a linked reference to the same file. Linked. Swept: no unlinked src/... references remain in the file.

match observation.coherence -- rejected

It compiles. This is the third round reporting this shape -- twice against diagnostic.rs, now against invariant.rs.

Matching a place expression behind a shared reference is a move only when a pattern binding moves a non-Copy value. All three arms here are unit-like or { .. } and bind nothing at all:

Coherence::Agreed => {}
Coherence::Disagreed { .. } => ...
Coherence::NotCollected => ...

Coherence not being Copy is not sufficient on its own. cargo check --all-targets is clean across the workspace and has been on every commit these lines have existed -- verified again this round before replying.

I have not added a no-op & to satisfy the claim. But a note now sits at the match explaining why it is correct: three review rounds spent on one false positive is itself evidence that the code should answer the question before it is asked a fourth time.

The suggestion that CrossCheck "already does" match by reference is a style difference, not a correctness one -- that site binds differently.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved moderate findings and documentation/comment nits remain.

Review details

Suppressed comments (8)

crates/windows-ioring-sys/tests/handover.rs:542

  • already_queued is measured only after completion_event() has returned, and drain_to_empty itself runs before the comparison. A read can therefore finish between the attach and this poll, so already_queued < width does not prove that any read was outstanding when the event was attached. The test can set caught_in_flight and pass its final guard while exercising only the already-completed/backlog path; establish the pending count immediately before the attach (or otherwise synchronize the precondition with the attach boundary).
            if already_queued < width {
                caught_in_flight = true;

crates/windows-platform-probes/CHECKLIST.md:31

  • These newly added historical dates omit the time and offset, even though this PR adds the repository rule that dates written to tracked documents must be UTC or offset-bearing. Please use the actual offset-bearing timestamp, or describe this as a relative milestone event without a date.
  above was rewritten on 2026-09-13 to match**: it still asked for "the same correspondence

crates/windows-platform-probes/CHECKLIST.md:55

  • These newly added historical dates omit the time and offset, even though this PR adds the repository rule that dates written to tracked documents must be UTC or offset-bearing. Please use the actual offset-bearing timestamp, or describe this as a relative milestone event without a date.
  `every_numa_counter_branch_...` were narrowed on 2026-09-13 to stop overstating the coverage,

crates/windows-platform-probes/CHECKLIST.md:237

  • These newly added completion links use bare local dates, despite the timestamp rule added by this PR requiring UTC or an explicit offset for dates written to repository documents. Please update each completion stamp with its actual offset-bearing timestamp before merging.
- [x] **M2.14** -- Make the two authoring rules this branch earned actually bite. -> [completed 2026-09-13](COMPLETED-CHECKLIST.md#m214)

- [x] **M2.14.1** -- Give this crate a sabotage manifest, so "observed to fail" is a recorded artifact rather than a habit. -> [completed 2026-09-13](COMPLETED-CHECKLIST.md#m2141)

- [x] **M2.14.2** -- Add to CONTRACT INTEGRITY rule 1 the one thing this branch learned that it does NOT already say. -> [completed 2026-09-13](COMPLETED-CHECKLIST.md#m2142)

crates/windows-platform-probes/CHECKLIST.md:73

  • This new M4 placement says the item is unblocked by M3.1/M3.3, but its acceptance text below still requires expressing the relation in the deleted M2.1 prose oracle and says the work belongs to M2. M3 made the encoded row the contract, so the item is not actually re-scoped as the milestone header claims; update its acceptance criteria to the current observation/row design before it is executed.
  Gated by M3.1 and M3.3, both landed: establishing that the middle of three discoveries agreed
  produces a new FACT, which M3.1 says must reach the row rather than only the banner, and M3.3
  changed how the banner is built. Written before those, it would have been written into machinery

crates/windows-platform-probes/COMPLETED-CHECKLIST.md:527

  • This newly archived Moved heading uses a bare date, unlike the adjacent timestamped archive entries. Include the UTC time or an explicit offset in new archive headings so the recorded completion instant is unambiguous.
## Moved 2026-09-12 -- M3: the encoded row became the contract, and the prose stopped being checked

crates/windows-platform-probes/src/report_oracle.rs:235

  • keys invokes deserialize_map but never calls Deserializer::end(). serde_json stops after the first value, so keys(r#"{\"reason\":\"x\"}garbage"#) returns the object's keys even though check/malformation reject the same row. This makes the public key reader accept a malformed artifact and lets callers disagree about whether the row is readable; finish the deserializer and reject trailing tokens.
    let mut reader = serde_json::Deserializer::from_str(row);
    serde::Deserializer::deserialize_map(&mut reader, TopLevelNames).unwrap_or_default()

crates/windows-platform-probes/src/topology.rs:618

  • The newly added MeasuredButCountsAbsent entry makes the preceding explanation stale: a zero counter is now added to parse_incomplete, and parse_in_doubt() is true for any non-empty parse_incomplete. As written, the comment incorrectly says this case is only not_compared and leaves parse_in_doubt false, which can mislead future changes to this guard.
        if self.topology_was_measured && !absent.is_empty() {
            check
                .parse_incomplete
                .push(ParseIncomplete::MeasuredButCountsAbsent { absent });
  • Files reviewed: 23/25 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Mike Grier and others added 2 commits September 14, 2026 01:21
…eview read it backwards

`already_queued < width` sets `caught_in_flight`, and a review argued it does
not prove a read was outstanding at the attach: a read finishing between the
attach and the poll would, on that reading, let the test pass while exercising
only the already-completed path.

The direction is what settles it, and it runs the other way.

`drain_to_empty` loops until `try_pop` reports the queue EMPTY -- no cap, no
early exit -- so `already_queued` is the total observed at a moment strictly
after the attach. A read finishing in that window is therefore COUNTED, which
pushes `already_queued` toward `width` and makes the branch LESS likely to be
taken. The already-completed case the finding warns about is exactly the case
where all `width` are drained and the flag is never set.

So the error this can make is a false NEGATIVE, never a false positive. And
completion is monotonic: a read still outstanding at the later poll was
outstanding at the earlier attach. The escalation over widths and attempts, and
the final assertion, exist for the false negatives.

The one real assumption is that `try_pop` reports emptiness truthfully -- a ring
claiming empty while holding completions would forge this precondition. That is
a defect in the crate under test rather than in the test, and
`contract.assert_quiescent()` is what would catch it. Written down because it is
the only way this argument fails.

Comment only; no behaviour change. Typed `chore` because
`tools/check-commit-scope.ps1` flagged it riding along with unrelated
`windows-platform-probes` work.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`keys` called `deserialize_map` and never `Deserializer::end()`. `serde_json`
stops at the end of the first value and does not care what follows, so two
public readers disagreed about the same artifact. Measured before fixing:

    keys(r#"{"reason":"x-probe-topology"}garbage"#)  ->  ["reason"]
    check(...)  ->  Malformed { what: "trailing characters at line 1 column 30" }

A caller reading keys directly was told a malformed row was readable. Reported
by a review. `keys` now returns nothing when tokens follow the object, with a
control asserting the same row WITHOUT the garbage still reads normally.

The sabotage manifest anchored on the two lines this changed, so its entry was
rewritten and re-verified: all eight anchors resolve, and entry 3 still
compiles and is CAUGHT (nine tests fail) rather than becoming unviable. The
explanatory comment moved above the block so the anchor stays pure code -- a
substitution that has to skip a comment is one that silently stops matching
when the comment is edited.

**A stale motivation in `cross_check`, written in the present tense.** The
paragraph over the `MeasuredButCountsAbsent` push said a zero parse beside a
failed read "is filed as `not_compared` -- leaving `parse_in_doubt` false". That
described the gap the push CLOSES, sitting directly above the push that closes
it, so it read as current behaviour. Put in the past tense, with the effect on
`parse_in_doubt` stated.

**M2.5's acceptance criteria still named the deleted M2.1 prose oracle**, the
same defect M2.4 carried and the same fix: the relation belongs in M3.2's
invariant set and the row schema, checked through the renderer binding. Swept --
no remaining item ASKS for the retired machinery.

Two newly added prose dates lost their bare form in favour of relative wording
("when M3 was archived", "in the same review round that reported this"), which
is both offset-free and more durable than either date form.

Two further findings were REJECTED. The stub links `[completed 2026-09-13]` use
a bare date because that IS the stub format the repository rules specify; and
`COMPLETED-CHECKLIST.md`'s `## Moved 2026-09-12` heading predates the timestamp
rule, which says in terms that existing headings "are fine and are not worth
going back to change" -- and editing it would breach that file's append-only
invariant. The same heading was raised and answered two rounds ago.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 14, 2026 08:22
@MikeGrier

Copy link
Copy Markdown
Owner Author

Round 12 disposition: the eight suppressed comments

Four fixed, four rejected. Every one verified by running it, not by reading.

The in-flight precondition -- REJECTED, and the direction is what settles it

This was flagged to me as the important one, so I worked it through carefully. The concern: a read finishing between the attach and the poll lets the test pass while exercising only the already-completed path.

It runs the other way.

drain_to_empty loops until try_pop reports the queue empty -- no cap, no early exit -- so already_queued is the total observed at a moment strictly after the attach. A read finishing in that window is therefore counted, which pushes already_queued toward width and makes the branch less likely to be taken. The already-completed case the finding warns about is exactly the case where all width are drained and the flag is never set.

So the error this can make is a false negative, never a false positive -- and completion is monotonic, so a read still outstanding at the later poll was outstanding at the earlier attach. The escalation over widths and attempts, and the final assertion, exist precisely for the false negatives.

The one genuine assumption is that try_pop reports emptiness truthfully; a ring claiming empty while holding completions would forge the precondition. That is a defect in the crate under test, and contract.assert_quiescent() is what would catch it. All of this is now written at the site (c8f7e63), because it is the only way the argument fails and the next reader deserves it.

keys accepted a row the oracle rejects -- FIXED

The best finding in this round, and measured exactly as described:

keys(r#"{"reason":"x-probe-topology"}garbage"#)  ->  ["reason"]
check(...)  ->  Malformed { what: "trailing characters at line 1 column 30" }

Two public readers disagreeing about one artifact; a caller reading keys directly was told a malformed row was readable. Deserializer::end() added, with a control proving the same row without the garbage still reads normally.

That entry is one of the sabotage manifest's anchors, so I rewrote it and re-verified: all eight anchors resolve, and the entry still compiles and is caught (nine tests fail) rather than quietly becoming unviable. The explanatory comment moved above the block so the anchor stays pure code -- a substitution that has to skip a comment is one that stops matching the moment the comment is edited.

Stale motivation in cross_check -- FIXED

Right. The paragraph over the MeasuredButCountsAbsent push described the gap that push closes, in the present tense, sitting directly above it. Put in the past tense with the parse_in_doubt effect stated.

M2.5 still named the deleted M2.1 oracle -- FIXED

Right, and the same defect M2.4 carried. Its acceptance criteria now point at M3.2's invariant set and the row schema. Swept: no remaining item asks for the retired machinery.

Dates

The two newly added prose dates are gone in favour of relative wording, which is offset-free and more durable than either date form.

The other two are rejected:

  • [completed 2026-09-13] stub links use a bare date because that is the stub format the repository rules specify.
  • COMPLETED-CHECKLIST.md's ## Moved 2026-09-12 predates the timestamp rule, which says in terms that existing headings "are fine and are not worth going back to change" -- and editing it would breach that file's append-only invariant. Same heading raised and answered two rounds ago.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

A moderate test failure remains, and the broad contract and invariant changes warrant final human review.

Review details

Suppressed comments (1)

crates/windows-platform-probes/tests/a_real_report_agrees_with_itself.rs:484

  • serde_json::Value uses its default sorted map representation here, so ToString::to_string() reorders object members before this comparison. For example, Disagreement::published() renders code, parsed, counter, while the parsed value is serialized as code, counter, parsed; the disagreement shapes in shapes() therefore make this test fail even when the payload is correct. Compare parsed Values (or canonicalize both sides through the same serializer) instead of comparing order-sensitive strings.
    let parsed: serde_json::Value = serde_json::from_str(row).expect("the row parses");
    parsed[key]
        .as_array()
        .unwrap_or_else(|| panic!("`{key}` should be a list in:\n{row}"))
        .iter()
        .map(ToString::to_string)
        .collect()
  • Files reviewed: 23/25 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@MikeGrier
MikeGrier merged commit 326155b into main Sep 14, 2026
29 checks passed
@MikeGrier
MikeGrier deleted the mikegrier/probes-encoded-row-contract branch September 14, 2026 08:56
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.

2 participants