docs(readme): census the three concurrency-scenario shapes honestly
Three corrections to the methodology paragraph, all of the same kind: it stated as fact things that hold for some scenarios and not others. "Run the real scripts as real concurrent processes" is true of seed scenario 7 and half-true of 8a; 8b, prune 12 and publish 6-8 spawn nothing. A reader who stopped at that topic sentence would take away "spawn real concurrent processes", which is the instinct that produced #3. The paragraph now leads with the three shapes actually in use and says which scenarios take each: a genuine race whose invariant holds under any interleaving; a PATH stub that places the interference inside the window; and a synthetic stand-in for the other side where the artefact is itself the contract. That third shape — publish-snapshot-selftest.sh's held .reading-* marker — was unmentioned, so the README implied that suite stubs something it does not. Its own defence (the marker IS the contract between the two sides, and racing a real slow consumer would make the suite's runtime the thing under test) is a good reason and now sits beside the other two. "Where more than one guard could catch a fault, the scenario asserts which one did" was written as description when it is a target: seed scenario 9 does not, which is exactly why #5's mutation survives it. Stated as the rule plus its one live exception — a rule asserted as fact with a known counterexample is the same defect as the sentence this paragraph replaced.
This commit is contained in:
@@ -370,26 +370,43 @@ Every suite runs the actual script, not a reimplementation of its logic, and
|
|||||||
every fix scenario is paired with a control that reproduces the bug — a
|
every fix scenario is paired with a control that reproduces the bug — a
|
||||||
scenario that passes either way proves nothing.
|
scenario that passes either way proves nothing.
|
||||||
|
|
||||||
The concurrency scenarios run the real scripts as real concurrent processes,
|
The concurrency scenarios take one of three shapes, and none of them races
|
||||||
but they never race for the interleaving. The interfering step is placed
|
for the interleaving its assertion depends on.
|
||||||
inside the window by stubbing, on `PATH`, a command the code under test calls
|
|
||||||
at a known point: `prune-cache-selftest.sh` scenario 12 stubs `du`, so the
|
**A genuine race whose asserted invariant holds under any interleaving.**
|
||||||
pass's own measurement publishes a reader marker strictly between its check
|
`seed-target-dir-selftest.sh` scenario 7 starts two real seeds on one cache
|
||||||
and its unlink; `seed-target-dir-selftest.sh` scenarios 8a and 8b stub `cp`,
|
key and asserts only what must be true whichever of them wins the rename.
|
||||||
so the consumer's own clone is what rotates the snapshot underneath it, or
|
|
||||||
what loses a subtree of its own source, strictly inside the identity window.
|
**A `PATH` stub on a command the code under test calls at a known point**,
|
||||||
Placement is then a fact rather than a scheduling outcome — and each stub
|
which places the interference inside the window rather than hoping it lands
|
||||||
asserts that it fired, because a scenario whose interference silently did not
|
there. `prune-cache-selftest.sh` scenario 12 stubs `du`, so the pass's own
|
||||||
happen passes for the wrong reason.
|
measurement publishes a reader marker strictly between its check and its
|
||||||
|
unlink; `seed-target-dir-selftest.sh` scenarios 8a and 8b stub `cp`, so the
|
||||||
|
consumer's own clone is what rotates the snapshot underneath it, or what
|
||||||
|
loses a subtree of its own source, strictly inside the identity window. 8a
|
||||||
|
does start a second real process — the actual `publish-snapshot.sh` — but the
|
||||||
|
stub is what fixes where its swap lands; the concurrency is incidental to the
|
||||||
|
determinism. Every stub asserts that it fired, because a scenario whose
|
||||||
|
interference silently did not happen passes for the wrong reason.
|
||||||
|
|
||||||
|
**A synthetic stand-in for the other side, where that artefact *is* the
|
||||||
|
contract.** `publish-snapshot-selftest.sh` scenarios 6 to 8 hold a
|
||||||
|
`.reading-*` marker instead of running a slow consumer: the marker is the
|
||||||
|
whole agreement between reader and publisher, so holding one is being a
|
||||||
|
reader, and racing a real one would make the suite's runtime the thing under
|
||||||
|
test.
|
||||||
|
|
||||||
Gating the interfering step on *observed progress* of the step it interferes
|
Gating the interfering step on *observed progress* of the step it interferes
|
||||||
with was the earlier answer here, and it is not one: seeing that a walk has
|
with was an earlier answer here, and it is not one: seeing that a walk has
|
||||||
started says nothing about where it will be when the interference lands, so
|
started says nothing about where it will be when the interference lands, so
|
||||||
the assertion downstream held only some of the time (issue #3).
|
the assertion downstream held only some of the time (issue #3). No scenario
|
||||||
|
does it any more.
|
||||||
|
|
||||||
Where more than one guard could catch a fault, the scenario asserts *which*
|
Where more than one guard could catch a fault, a scenario should assert
|
||||||
one did — otherwise deleting the guard under test leaves the suite green
|
*which* one did — otherwise deleting the guard under test leaves the suite
|
||||||
because a sibling fires in its place.
|
green because a sibling fires in its place. Scenarios 8a and 8b of the seed
|
||||||
|
suite do; scenario 9 of the same suite does not yet, which is why a mutation
|
||||||
|
survives it (issue #5).
|
||||||
|
|
||||||
The action YAML holds no logic beyond wiring; everything testable lives in
|
The action YAML holds no logic beyond wiring; everything testable lives in
|
||||||
`scripts/`. A composite action needs `shell: bash` on every `run:` step, and
|
`scripts/`. A composite action needs `shell: bash` on every `run:` step, and
|
||||||
|
|||||||
Reference in New Issue
Block a user