Skip to content

docs: a control can be the thing that cannot fail, and a read-back needs a baseline - #4788

Merged
meshweaver-cloud[bot] merged 3 commits into
mainfrom
docs/sweep-verification-lessons
Sep 19, 2026
Merged

meshweaver-cloud[bot] merged 3 commits into
mainfrom
docs/sweep-verification-lessons

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Four lessons the merged-PR review sweep produced after #4779 had already landed, so they could not ride with it. Each came from a peer session measuring something, and two of them correct claims I made earlier in that same page.

🚨 A control can be the thing that cannot fail

Worse than a check that cannot fail, because a control is what you appeal to once you have stopped trusting the checks.

MeshWeaver.Education#335 said a liveness census could not parse its own heartbeat, so wedged was false by construction and the instrument reported a clean pool over a real wedge. It was written up, agreed with, and given a control: fed the tick lines the script's header quotes as a past incident's cause, it went from 0 of 5 wedged to 3 of 5, naming the window — so clean a swing it read as proof.

The parser was correct. ProcessLiveness.Describe() renders every delta parenthesised and gap always as actual/threshold; its unit test asserts the rendered line. The forms the control fed appear in no real log — it had been built from an abbreviated transcription in a comment, so it proved something about the transcription and nothing about the parser.

The distinction that would actually have stopped it is not "prose versus data". The header was a quoted log excerpt, which is exactly why it persuaded. So: an example that merely appears in the code under test is not a fixture. A fixture is something the producer wrote (a format string, a golden file) or something a test asserts — nothing else earns the name, however much it looks like captured output. Also recorded: size of effect is not evidence of validity, and the falsifying artefact was a sentence in that harness's own README, read afterwards while looking for somewhere to file the finding.

A read-back needs a baseline — the two-part key

The page reported "182 of 182 findings answered, proven by read-back" on a key that was a substantive reply exists on this thread. That half alone is unfalsifiable: it passes on a reply an earlier session left. What makes the number mean anything is the other half — the same 182 were measured unanswered at sweep start.

The baseline is not a caveat on the result, it is half the instrument. State both halves or neither, for any "N of N done" built by re-reading a store you also wrote to.

The safe form for posting

jq -Rs '{body:.}' into --input reads a file for every field and interprets no value. The one session of four that did this was the only one with no stub — it sidesteps the -f/-F question instead of requiring anyone to remember which flag reads a file.

Re-check the canonical before the merge, not only before the push

It moved twice in one morning (201,067 → 228,485), so three satellites re-copied, landed, and were stale again within the hour. Education's session checked before merging rather than after and found its own main still red at the intermediate size — the check that saved a pointless merge. The window between waves can be shorter than the time a pull request takes to go green.

Controls

Documentation.Test builds 0 Error(s) under -c Release -warnaserror; 6 tests pass, DocumentationLinkIntegrityTest included. Documentation-only — one file, 67 lines added, no code path touched.

🤖 Generated with Claude Code

…eds a baseline

The four lessons the merged-PR sweep produced after #4779 had already landed. Each came from a peer
session measuring something, and two of them correct claims I made earlier in that page.

A CONTROL THAT CANNOT FAIL is worse than a check that cannot fail, because a control is what you
appeal to once you have stopped trusting the checks. MeshWeaver.Education#335: a finding said a
liveness census could not parse its heartbeat, so the instrument reported a clean pool over a real
wedge. Agreed with, and given a control that swung 0-of-5 to 3-of-5 — so cleanly it read as proof. The
parser was correct; the control had been built from an abbreviated transcription in a comment, and the
forms it fed appear in no real log.

🚨 THE DISTINCTION THAT WOULD HAVE STOPPED IT is not "prose versus data" — the header was a QUOTED LOG
EXCERPT, which is exactly why it persuaded. An example that merely APPEARS in the code under test is
not a fixture; a fixture is something the PRODUCER wrote (a format string, a golden file) or something
A TEST ASSERTS. Nothing else earns the name however much it looks like captured output. Also recorded:
size of effect is not evidence of validity, and the falsifying artefact was a sentence in that
harness's own README, read afterwards while looking for somewhere to file the finding.

A READ-BACK NEEDS A BASELINE. This page reported "182 of 182 answered, proven by read-back" on a key
that was "a substantive reply exists" — unfalsifiable alone, since it passes on a reply an earlier
session left. What makes it mean anything is that the same 182 were measured UNANSWERED at sweep
start. The baseline is not a caveat on the result, it is half the instrument; state both halves or
neither.

THE SAFE FORM FOR POSTING is `jq -Rs '{body:.}'` into `--input`, which reads a file for every field
and interprets no value. The one session of four that did this was the only one with no stub — it
sidesteps the `-f`/`-F` question instead of requiring anyone to remember which flag reads a file.

RE-CHECK THE CANONICAL BEFORE THE MERGE, not only before the push: it moved TWICE in one morning
(201,067 -> 228,485), so three satellites re-copied, landed, and were stale again within the hour. The
window between waves can be shorter than the time a pull request takes to go green.

Controls: Documentation.Test builds 0 Error(s) under -c Release -warnaserror; 6 tests pass,
DocumentationLinkIntegrityTest included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 19, 2026 09:37
The twin of "a broken query reports not-yet forever", and worse, because this one triggers an ACTION.

Measured 2026-09-19 09:08:35Z on MeshWeaver.Plugins. A blob watcher armed as
`until [ "$(gh api "$P" --jq '.sha' 2>/dev/null || true)" != "$BASELINE" ]` fired a FALSE "ACT NOW —
the file moved": GitHub answered the secondary-limit 403, `--jq '.sha'` returned the error body, and
`!=` against the baseline was true. Nothing had moved, and the announcement named a remedy (merge and
push) that would have merged a stale canonical and burned a CI run during the very limit that caused
it.

THE POLARITY IS THE WHOLE DIFFERENCE, and it is as easy to get right by accident as wrong:
  until [ "$(read)" = "true" ]        403 -> predicate FALSE -> keeps waiting. Annoying, SAFE.
  until [ "$(read)" != "$baseline" ]  403 -> predicate TRUE  -> FIRES. Unsafe.
Verified both arms empirically with the real 403 body substituted. My own five waiters today took the
equality form and failed safe — by luck of phrasing, not by design, which is why this is worth stating
as a rule rather than left to taste.

So: write the condition so a failed read is FALSE, never TRUE — wait for the value you EXPECT, never
for DIFFERENCE from a value you remember. Where difference is genuinely needed, shape-guard first (a
sha is 40 hex; a size is digits) and make "could not read" its own printed outcome that backs off,
rather than a silent third state folded into one of the other two.

The question to ask before arming any watcher is one line: WHAT DOES THIS PRINT ON A 403? Ask it of
the whole expression, including the `|| true` added so a transient failure would not kill the loop —
that fallback is usually where the defect enters.

Controls: Documentation.Test builds 0 Error(s) under -c Release -warnaserror; 6 tests pass,
DocumentationLinkIntegrityTest included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.

Copilot review overview

🟡 Changes recommended

Fix payload-generation failure handling and clarify the inaccurate documentation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Low severity

Open (1)
What changed in this PR

Documentation-only update covering four review-process lessons.

Changes:

  • Clarifies trustworthy controls and read-back baselines.
  • Documents safer JSON payload construction.
  • Emphasizes canonical verification before merging.
File Summary
src/​MeshWeaver.Documentation/​Data/​Architecture/​ReviewFindingsAnswered.md Adds the four operational lessons.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +517 to +518
Build the payload as JSON and hand it to `--input`, which reads a file for every field and never
interprets a value:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct, and the error is worse than imprecise — it is wrong about the mechanism in the one section whose whole purpose is to state the mechanism unambiguously.

I wrote that --input "reads a file for every field and interprets no value". It does not. --input
takes one file that is the complete request body; there are no per-field semantics to it at all.
What the recipe actually does is build the whole JSON body with jq -Rs '{body:.}' — which is where
the safety comes from, because jq does the quoting and escaping — and then hand that one body to
--input. My sentence attributed the safety to the wrong half of the pipeline, which would have left
a reader believing --input itself confers protection on fields generally.

Fixing the wording to describe it as handing the generated JSON body to --input, as you say.

And thank you for landing on this section specifically, because the finding exposes a second defect in
it that you could not have seen from the diff. Its neighbouring paragraph tells readers the stub
discriminator is a body starting with @. That is only half the mechanism:

  • -f body=@file sends the literal @file — the stub starts with @;
  • -F body="$file" with the @ omitted sends the path itself — the stub starts with /.

-F reads a file only with the @ prefix, so dropping it silently turns the path into the value.
A sweep keyed on ^@ misses the second kind entirely, and I have just re-audited on the broader
discriminator rather than assume my earlier 0 of 495 covered it. Both mechanisms and both first
characters will be named in the fix, since a rule keyed on one flag would have missed the worse
instance.

Replying before pushing, deliberately: the pull_request review run fires on the push, so a fix
pushed while this thread is unanswered makes the one run branch protection reads red by construction.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

0 tests   - 1 553   0 ✅  - 1 553   0s ⏱️ - 3m 12s
0 suites  -     2   0 💤 ±    0 
0 files    -     2   0 ❌ ±    0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

0 files   -     3  0 suites   - 3   0s ⏱️ - 5m 43s
0 tests  - 1 857  0 ✅  - 1 857  0 💤 ±0  0 ❌ ±0 
0 runs   - 1 858  0 ✅  - 1 858  0 💤 ±0  0 ❌ ±0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

0 tests   - 438   0 ✅  - 438   0s ⏱️ -58s
0 suites  -   3   0 💤 ±  0 
0 files    -   3   0 ❌ ±  0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

0 files   -     5  0 suites   - 5   0s ⏱️ - 11m 53s
0 tests  - 3 679  0 ✅  - 3 677  0 💤  - 2  0 ❌ ±0 
0 runs   - 3 683  0 ✅  - 3 681  0 💤  - 2  0 ❌ ±0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

601 tests   - 109   601 ✅ + 83   20s ⏱️ - 5m 14s
  1 suites  -   2     0 💤  - 192 
  1 files    -   2     0 ❌ ±  0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

265 tests  ±0   265 ✅ ±0   2m 50s ⏱️ +30s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Test Results

  2 files   -    15    2 suites   - 15   3m 11s ⏱️ - 26m 31s
866 tests  - 7 636  866 ✅  - 7 442  0 💤  - 194  0 ❌ ±0 
866 runs   - 7 641  866 ✅  - 7 447  0 💤  - 194  0 ❌ ±0 

Results for commit 7dbe919. ± Comparison against base commit 1da61b3.

♻️ This comment has been updated with latest results.

Copilot's finding was right, and wrong in the worst available place — the section whose whole purpose
is to state the safe invocation unambiguously.

I wrote that `--input` "reads a file for every field and never interprets a value". It does not:
`--input` takes ONE file that IS the complete request body, with no per-field behaviour to confer any
protection. The safety in that recipe is `jq`'s — it does the quoting and escaping, so no value can be
read as a flag argument. Attributing it to `--input` would have left a reader believing the flag
protects fields generally. Now described as building the whole body with `jq` and handing that one
file to `--input`.

AND THE FINDING EXPOSED A SECOND DEFECT in the same section, which the diff could not show. Its
neighbour told readers the stub discriminator is a body starting with `@`. That is half the mechanism:

  -f body=@reply.md          sends the literal `@reply.md`     stub starts with @
  -F body="$file"  (no @)    sends the path itself             stub starts with /

`-F` reads a file ONLY with the `@` prefix, so dropping it silently turns the path into the value — and
that is the worse instance, because it looks less obviously wrong. A sweep keyed on `^@` cannot see it.

So the page no longer keys on a flag or on a prefix; it keys on the SHAPE of the body — a reply that is
a single token with no whitespace is a path, whatever put it there. I re-audited on that key rather
than assume my earlier `^@` pass covered it: 0 of 533 comments authored during the sweep are stubs. The
number survives; it now survives for a reason rather than by luck, and the earlier pass could not have
said so.

The reply went on the thread BEFORE this push, so the `pull_request` review run fires against an
answered thread rather than making the one run protection reads red by construction. The reply itself
was verified by taking `id` from the POST response, re-fetching by that id, and byte-comparing against
the file — identical.

Controls: Documentation.Test builds 0 Error(s) under -c Release -warnaserror; 6 tests pass,
DocumentationLinkIntegrityTest included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@meshweaver-cloud
meshweaver-cloud Bot added this pull request to the merge queue Sep 19, 2026
Merged via the queue into main with commit 96fecc2 Sep 19, 2026
37 checks passed
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