Skip to content

test(flow): consult a SYNC flow target for real, and close criterion 5's read half (#112) - #960

Merged
ELares merged 8 commits into
mainfrom
feat/112-sync-fixture
Aug 22, 2026
Merged

test(flow): consult a SYNC flow target for real, and close criterion 5's read half (#112)#960
ELares merged 8 commits into
mainfrom
feat/112-sync-fixture

Conversation

@ELares

@ELares ELares commented Aug 22, 2026

Copy link
Copy Markdown
Owner

What

Closes the test half of #112. An audit of its six acceptance criteria found four
unmet for a single reason: with_flow_target_fetcher had exactly one caller in
the tree, the boot path, and no test installed it. So consult_target had ZERO
callers in the whole suite, and dispatch_sync past its no-fetcher branch was
dead code from the tests' point of view. The half of the feature that can reject
a signup in band shipped with no behavioural test at all.

This adds crates/ironauth-oidc/tests/flow_target_sync.rs (7 tests) driving real
registrations through a real fetcher at BOTH signup doors, plus the criterion 5
read-half pin and the secret_shaped_key guard the audit found untested.

Criteria this moves

# criterion before now
1 sync target consulted on registration no test installed the fetcher driven end to end at both doors
3 failure policy honoured untested refuse and fail-open driven, at both doors
4 timeout triggers the policy untested driven, and the CONFIGURED bound is pinned
5 config never re-encodes secrets WRITE half only read half pinned; secret_shaped_key closed
6 consultation reaches the network untested dialer records the attempt

Notes for the reviewer

  • Criterion 5's read half was green while broken. Nothing anywhere asserted a
    field of FlowTargetView, so returning base64 from the listing (the exact
    affordance the criterion forbids) passed the whole suite. The fixture carries a
    value that LOOKS like code on purpose: a config of {"a":1} cannot distinguish
    a structured object from a re-encoding.
  • secret_shaped_key had zero test references. fn secret_shaped_key(_) -> None
    survived the entire suite. The NESTED case is what is driven, because a
    top-level-only check passes a config whose secret sits one level down, which is
    where a copied snippet puts it. Paired with a clean nested config that must be
    accepted, so the refusal is the guard talking rather than nesting itself.
  • No test can complete an HTTPS exchange here, by design. Fetcher::for_tests
    and from_parts both use an empty root store, so these tests assert that the
    consultation REACHES the network, not that it gets an answer. That ceiling is
    filed as No test can complete an HTTPS exchange through the hardened fetcher, blocking two #112 criteria #959 and is why the answering-target mode was deleted rather than
    #[allow(dead_code)]-ed: leaving it would be a false affordance.
  • One commit restores two generated artifacts a killed regeneration had emptied
    (catalog.json -2888, log-stream-vectors.json -85). Both are byte-identical
    to main, which is correct because this branch adds no events and no vectors.

Review round 1 found four defects, all fixed here

A four-lens fresh-eyes review, each finding handed to a separate verifier told to
refute it: 21 raised, 11 refuted, 10 confirmed, deduping to four. The two that
mattered:

  • The per-target timeout was unmeasured. The criterion 6 test asserted only the
    signup outcome, so nothing was sensitive to WHICH deadline fired. Changing
    .min(budget_remaining_ms) to .max(..) in consult_target compiles
    warning-free, requests the whole ~45s budget instead of the configured 250ms, and
    the never-answering server still times out against the fetcher's own ceiling. All
    five tests stayed green. Now pinned with an elapsed-time assertion stated as a
    multiple of the test's OWN configured bound, so raising a default elsewhere can
    never silently widen the guard.
  • Only one of the two signup doors was driven. The legacy POST /register and
    the flow API have separate dispatch_sync call sites, and the flow door had zero
    test callers. Two tests added there, refuse and admit, so the refusal is
    attributable to the policy rather than to the door.

Also fixed: the file header claimed a mutation kill the file cannot make (JSON
pointer resolution, unreachable behind the empty root store and unreachable on the
legacy door in principle), and a new harness method had been inserted between
install_hashing_pool's doc comment and its signature, leaving one function
misdocumented and the other undocumented.

Verification

  • flow_target_sync 7/7, flow_target_delivery 21/21, full DB suite set green.
  • Both new guards are mutation-verified, each restored byte-identical afterwards:
    • widening the per-target bound (.min to .max) turns the criterion 6 test red
      with took 10.009049042s, allowed 5s, which is the fetcher's 10s default
      stepping in exactly as predicted;
    • making the flow door's Refuse arm fall through turns the fail-closed door test
      red while the fail-OPEN control stays green (1 passed; 1 failed), so the pair
      discriminates the policy rather than the door.
  • All static gates pass, including event-catalog.sh and log-stream-vectors.sh.
  • test-registration.sh floor raised 288 to 289, snug against the new count.

ELares and others added 4 commits August 21, 2026 21:53
An audit of #112's six acceptance criteria found four unmet for ONE reason:
with_flow_target_fetcher had a single caller in the tree, the boot path, and no
test installed it. So consult_target had ZERO callers in the whole suite and
dispatch_sync past its no-fetcher branch was dead code from the tests' point of
view. The half of this feature that can approve or reject a signup IN BAND had
no behavioural test at any of the four places coverage lives here.

Five tests, each paired so its assertion is attributable to the thing it names:

  - a refusing PRE-PERSIST target leaves NO ROW, which is the observable half of
    criterion 4 (storing both timing values is only selectability), paired with
    a fail_open target that admits so the refusal is the policy talking;
  - a target that accepts and never answers ELAPSES its budget and triggers the
    policy, which is criterion 6, paired the same way. Outcome::Unavailable was
    never once produced BY a timeout anywhere in the suite before this -- only
    typed in as a literal in unit tests of apply_policy, which tests the mapping
    and not the timeout;
  - the consultation reaches the network, dialing the address destination
    validation approved rather than the loopback the dialer forwards to.

Mutation-verified, four for four. Transport failure returning Outcome::Allow --
a fail-closed fraud gate silently admitting the signup it exists to stop --
CAUGHT. The no-fetcher branch treated as a skip, which the source comment
predicted would "silently disarm every fail-closed target", CAUGHT. fail_closed
mapped to Continue, caught twice. Deleting the pre-persist dispatch from the
legacy door, caught three ways.

Criterion 3's SYNC half is NOT closed and the test says so rather than implying
otherwise. Completing an HTTPS exchange through the hardened fetcher is not
possible in this repository: from_parts builds its client with test_tls_config,
whose root store is EMPTY by design ("not one completes a handshake to a public
host"), and http:// is correctly refused by the plaintext policy. So an
in-process target can be dialed but never spoken to. That is a limit of the test
seams, not of the feature, and it is why this fixture was never written.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The WRITE half was pinned; the READ half was not. Nothing anywhere asserted a
field of FlowTargetView, so returning base64 from the listing -- the exact
affordance criterion 5 exists to forbid -- was green against the whole suite.
The fixture deliberately carries a value that LOOKS like code, because a config
of {"a":1} cannot distinguish a structured object from a re-encoding.

Also closes the secret_shaped_key guard, which the audit found had ZERO test
references: `fn secret_shaped_key(_) -> None` survived the entire suite, which
would let a pasted credential reach the listing, the delivered payload, and --
since D-1 -- a durable outbox row. The NESTED case is what is driven, because a
top-level-only check passes a config whose secret sits one level down, which is
where a copied snippet puts it. Paired with a clean nested config that must be
accepted, so the refusal is the guard talking rather than nesting itself.

Mutation-verified: both guards caught.

The listing mutant took three attempts, and the reason is worth recording. Twice
it reported ANCHOR 0 SKIPPED because I reconstructed the anchor text from memory
of the code rather than reading the bytes -- and a skip sits in the same column
as CAUGHT in a results table, so a sweep that mutates nothing looks like a sweep
that passes. The harness now locates the line by matching l.strip(), preserves
the file's own indentation, and asserts the text actually changed before running.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Clippy flagged `Behavior::Answer` as never constructed, and it was right for a
reason worth keeping rather than suppressing: the hardened fetcher cannot
complete a handshake with an in-process server, so no test can ever be answered.
An `#[allow(dead_code)]` would have left a false affordance in the file --
someone would later write a test against it and wonder why the target never
replies.

The helper now says what it is: a target that accepts and never answers, with
the reason and issue #959 in its own doc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two commits on this branch staged ZERO-LINE generated files:

  docs/events/catalog.json                        -2888
  packages/ironauth-sdk/vectors/log-stream-vectors.json  -85

Both had the same cause. A regenerating script was killed by a foreground
timeout mid-write, leaving the file truncated, and a later `git add -A` swept it
into a commit about something else entirely. Nothing in the commit message or the
change under review hinted that a published artifact had been deleted.

Both are restored by regenerating, and both are byte-identical to origin/main,
which is the correct end state precisely because this branch adds no events and
no log-stream vectors.

Worth recording how close this came to merging. The catalog failure surfaced only
because the gate diff named `webhook_endpoint.subscription_changed`, an event this
branch never touches, which is what made it clear the artifact rather than the
registry was wrong. The vectors file then slipped past my own first sweep for the
same defect, because I searched with a >100-line threshold and this deletion was
85 lines. A threshold chosen to find the bug I had already seen was blind to the
identical bug one file over; the correct filter is "insertions == 0", which has no
magnitude in it at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ELares

ELares commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Fresh-eyes review, round 1

Four independent lenses over the diff, each finding then handed to a separate verifier told to REFUTE it. 21 raised, 11 refuted, 10 confirmed, which dedupe to four distinct defects. All four are real. Fixing all of them in this PR.

1. The per-target timeout is unmeasured (HIGH, found by three lenses independently)

flow_target_sync.rs:240. The criterion 6 test registers timeout_ms = 250 and then asserts only the signup outcome. Nothing it asserts is sensitive to WHICH deadline fired.

The verifier's demonstration is a one-character change: .min(budget_remaining_ms) to .max(budget_remaining_ms) at flow_target.rs:394. It compiles warning-free, so -D warnings does not catch it. With one target the budget is ~45000ms, so 250.max(45000) requests 45s; ironauth-fetch/src/lib.rs:507 only ever SHORTENS a requested timeout, so the test fetcher's FetchLimits::default() ceiling of 10s applies instead. The never-answering server still times out, still yields Outcome::Unavailable, still refuses. All five tests stay green, 40x slower.

This matters beyond the test: criterion 6 reads "exceeding its timeout triggers the configured failure policy INSTEAD OF HANGING THE FLOW", and the boot path builds its fetcher with a 30s ceiling (main.rs:1353). The same mutant holds a live registration for 30s against an operator's configured 250ms. The module's own doc says it: "its bound is a promise to the person waiting."

So the PR's criteria table overclaims row 4. The tests prove an elapsed consultation triggers the policy rather than returning Allow, with a fail-open control. They do not prove the operator's bound is what ended it.

2. Only one of the two signup doors is driven (HIGH)

flow_target_sync.rs:149. There are two doors and each has its own dispatch_sync call site: the legacy /register path and the flow API (flow/mod.rs:93). This file pins only the legacy one. The async sibling file already learned this and pins both.

3. The header claims a kill the file cannot make (MEDIUM)

flow_target_sync.rs:29. The block is titled "The mutations these tests exist to kill" and says "Each was green against the whole suite before this file". The third bullet, JSON pointer resolution against no form, stays green: it lives in classify_response, reachable only after a successful fetch, which the empty-root-store ceiling forbids. It is also unreachable in principle on this route, since flow/mod.rs:99 passes None for the signup form.

That is the same unmeasured-sentence defect this PR exists to remove, so it has to go.

4. A doc comment was stolen from its function (MEDIUM, found by three lenses)

common/mod.rs:1025. install_flow_target_fetcher was inserted BETWEEN install_hashing_pool's doc block and its signature. So the new helper now opens with five lines about an Argon2id hashing pool and per-tenant fair-share admission, and install_hashing_pool ships with no doc at all. Two artifacts wrong from one bad edit anchor.

Accepted, not a finding

The empty-root-store TLS ceiling (#959) was ruled out of scope up front and the verifiers correctly refused findings that restated it.

ELares and others added 2 commits August 21, 2026 23:34
…nup door

Round 1 of fresh-eyes review raised 21 findings; verifiers told to refute them
killed 11, leaving 10 confirmed that dedupe to four. All four are fixed here.

**The per-target timeout was unmeasured.** The criterion 6 test registered a 250ms
bound and then asserted only the signup outcome, so nothing it checked was
sensitive to WHICH deadline fired. Changing `.min(budget_remaining_ms)` to
`.max(..)` in `consult_target` compiles without a warning, asks for the whole ~45s
budget instead of the configured 250ms, and the never-answering server still times
out against the fetcher's own ceiling. Every assertion stayed green and the suite
merely ran slower. In production the boot fetcher's ceiling is 30s, so that
one-character change holds a live registration 30s against a 250ms setting.

Now timed, with the ceiling stated as a multiple of the test's OWN configured bound
rather than of the fetcher default, so raising that default elsewhere can never
silently widen the guard. Mutation-verified: the mutant reports
"took 10.009049042s, allowed 5s", which is the fetcher's 10s default stepping in
exactly as predicted.

**Only one of the two signup doors was driven.** The legacy `POST /register` route
and the flow API have separate `dispatch_sync` call sites, and the flow door had
zero test callers. They are not interchangeable: the legacy door passes `None` for
the signup form and collapses an interruption to Refuse, so it cannot reach the
field-mapped path at all. Two tests added at the flow door, refuse and admit, so
the refusal is attributable to the POLICY and not to the door. Mutation-verified by
making the Refuse arm fall through: the fail-closed test goes red while the
fail-open control stays green, which is what makes the pair discriminating.

**The header claimed a kill the file cannot make.** It listed JSON pointer
resolution among "the mutations these tests exist to kill". That one stays green:
it lives in `classify_response`, reachable only after a successful fetch, which the
empty root store forbids, and it is unreachable on the legacy door in principle
since `dispatch_registration_targets` passes `None` for the form. Replaced with an
explicit "what this file does NOT kill, and why" section. Claiming a kill the file
cannot make is the same unmeasured sentence this file exists to remove, and it is
worse than silence: the next reader takes it as covered and stops looking.

**A doc comment was stolen from its function.** `install_flow_target_fetcher` had
been inserted between `install_hashing_pool`'s doc block and its signature, so the
new helper opened with five lines about an Argon2id hashing pool and
`install_hashing_pool` shipped undocumented. Two artifacts wrong from one bad edit
anchor. Each block now sits above the function it describes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…brary

`scripts/invariant-lints.sh` enforces a `time-via-env` rule: all wall-clock and
monotonic time in this workspace flows through the `Clock` trait in ironauth-env,
so protocol logic stays deterministic under test. The rule budgets exactly two raw
uses, which are the production `Clock` impl itself. My elapsed-time guard added a
third and the gate caught it.

Rewired through `harness.env().clock().monotonic()`, which is the same clock
`dispatch_sync` reads to measure the very span this test is checking. That is
strictly better than the raw call: the test now measures time the way the code
under test measures it, rather than from a second, independent source.

Monotonic rather than wall clock for the reason the dispatcher gives at its own
call site: an NTP step backwards would make the measured span exceed a budget
nothing was actually slow for.

One wrinkle worth recording, because it cost a cycle. The lint is a TEXT SCAN, so
the first fix still failed: the comment explaining why the raw constructor is
avoided contained the constructor's name, and the scanner counted it. The comment
is now worded to describe the rule without spelling the token, and says so, since
the next person to write that sentence will hit the same wall.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ELares

ELares commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Fresh-eyes review, round 2

Round 1's fixes are themselves changes that had never been reviewed, so this pass audits the fix commit rather than the original PR. Three lenses, each finding handed to a separate verifier told to refute it. 13 raised, 12 refuted, 1 confirmed.

The one confirmed finding was already fixed, independently

flow_target_sync.rs:279 broke the time-via-env invariant: this workspace routes all monotonic time through the Clock trait so protocol logic stays deterministic under test, and the rule budgets exactly two raw uses, which are the production impl itself. My round-1 elapsed guard added a third, reddening both scripts/gate.sh:393 and the unconditional invariants job at .github/workflows/ci.yml:599.

The gate caught this while the review was still running, and it is fixed in 1a275eb. Worth noting the reviewer proposed a different remedy: add an invariant-allow marker and raise the ceiling from 2 to 3. I took the other route, harness.env().clock().monotonic(), which is better on two counts. It spends no exemption, so the budget stays at 2/2 and the next person who needs one still has the argument available. And it makes the test read the very clock dispatch_sync reads to measure the span under test, rather than timing from an independent source.

The reviewer also independently hit the trap I did: an intermediate version of the fix put the forbidden token inside a comment, and the lint is a plain text scan with no comment awareness. Two of us walking into the same hole is a good argument for the note now sitting in that comment.

Three refuted findings I am overriding, having checked them myself

Recurrence across independent lenses made these worth re-checking, and all three are factually right. The verifiers refused them as style; in a PR whose entire subject is prose drifting from behaviour, they are in scope.

  1. HANG_TIMEOUT_MS's doc overclaims. It reads "the per-target bound the hanging-target tests configure", but lines 342 and 387 still pass a bare 250. Raising the constant would leave two tests on the old value, which is the same class of defect as the header claiming a kill it cannot make.
  2. "the empty root store described above" has no antecedent above it. Line 37 makes the reference; the first mention of the root store is line 75, below it.
  3. The ceiling goes inert at HANG_TIMEOUT_MS = 500. 250 * 20 is 5s against a 10s fallback. At 500 the ceiling becomes exactly the fallback and the guard stops discriminating, silently. Being a multiple of the right number does not make it safe at every value of that number.

Fixing all three, with a compile-time assertion for the third so the failure is a build error naming the problem rather than a guard that quietly stops working.

Notable refutations

The strongest was against a claim that the elapsed guard is an upper bound only and so misses a mutant that SHORTENS the honoured bound. True of any upper bound, but the verifier showed each load-bearing limb fails on the actual code. A claim that both flow-door tests pass with no fetcher installed was also refuted on inspection of the helper.

ELares and others added 2 commits August 22, 2026 00:05
…right anyway

Round 2 raised 13, refuted 12, confirmed 1. The confirmed one was the
`time-via-env` break, already fixed in 1a275eb. These three were REFUTED as
style. They recurred across independent lenses, so I checked them against the
file, and all three are factually correct. In a change whose whole subject is
prose drifting from behaviour, a doc that overclaims is the defect and not a
cosmetic note about it.

**`HANG_TIMEOUT_MS`'s doc overclaimed.** It reads "the per-target bound the
hanging-target tests configure", while two of them still passed a bare `250`.
Raising the constant would have left those two on the old value: the same shape
as the header claiming a kill the file cannot make, which round 1 removed. Both
now take the constant.

**A cross-reference pointed the wrong way.** "the empty root store described
above" sat at line 37; the first mention of the root store was line 75, below it.
Reworded to say the thing rather than point at a description that does not precede
it.

**The elapsed ceiling could go inert without anyone noticing.** It is stated as
`HANG_TIMEOUT_MS * 20`, which is 5s against the fetcher's 10s default. That is a
guard at 250. At 500 the product is EXACTLY the default, and the assertion would
pass whether the consultation was bounded by the target or by the fallback, which
is the entire distinction it exists to draw. Being expressed as a multiple of the
right constant does not make it safe at every value of that constant.

Now checked at compile time against the real constant, with half the default as
the margin so the two are never merely adjacent. Verified the guard can actually
fail rather than only pass: at 250 the suite builds, and at 500 the build stops
with `error[E0080]` naming the reason. A compile-time assertion nobody has watched
fail is just an expression.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Round 3 found a HIGH regression I introduced in round 2's own fix, and neither the
suite nor the gate could see it.

`1a275ebb` rewired the elapsed measurement to `harness.env().clock().monotonic()`
to satisfy the `time-via-env` invariant. It compiled, the suite stayed green 7/7,
and the full gate passed 52 static checks. The guard was dead. `Harness::start`
installs `Env::deterministic`, whose `ManualClock` moves only when a test calls
`advance`, and nothing here does. Both reads returned the same instant, so
`elapsed` was permanently zero and the assertion had degraded to `0 < 5s`. The
mutant round 1 added this guard to kill was quietly alive again.

A vacuous assertion PASSES, so a green suite and green static scans were both
entirely consistent with the defect, and there is no mutation lane in CI. Only
reading the harness finds it.

Real monotonic time restored, with the `invariant-allow` marker this repo already
grants a timing harness. That precedent is not a loophole: `outbound_timing_probe.rs`
states my exact case, that the Clock seam has no monotonic elapsed and injecting one
would measure the seam. The scan ceiling goes 2 to 3 for it.

**And a structural fix rather than only a repair.** An upper bound is satisfied by
zero, so it cannot detect its own death: `elapsed < ceiling` passes when the clock
stops, when the await is deleted, when the measurement never starts. There is now a
LOWER bound too. Against a target that never answers, a correctly bounded
consultation cannot return materially faster than its own bound. The floor is what
makes the ceiling falsifiable.

Two prose defects from the same review, both mine:

- the NTP rationale named the wrong direction. A step BACKWARDS shrinks a measured
  span; it is a forwards step that inflates one. Now states both and what each does.
- the const-assert doc was wrong by a factor of ten, claiming the build breaks past
  "a quarter of the default" (2500) when the assertion admits 250 and breaks at 251.
  It now states the real threshold and that the bound and multiple are tuned together.

Re-verified on THIS tree rather than a superseded one, which is the other half of
the lesson: I had gone on citing a CAUGHT verdict measured before the clock swap,
and editing a guard invalidates the measurement that justified it.

  1. suite with the restored measurement and the floor: 7 passed
  2. `.min` -> `.max`: CAUGHT, "took 10.00690525s, allowed 5s"
  3. reverting to the frozen Env clock: CAUGHT by the new floor, "returned in 0ns,
     faster than half its 250ms bound ... or the clock being read does not advance,
     which would make the ceiling assertion above vacuous"

The third is the one worth keeping: the guard can now detect the exact failure that
got past two review rounds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ELares

ELares commented Aug 22, 2026

Copy link
Copy Markdown
Owner Author

Fresh-eyes review, round 3

Two commits landed after round 2 closed and had never been reviewed, so this pass audits only that delta. 7 raised, 4 confirmed. The headline finding is a HIGH regression that I introduced myself in round 2's own fix, and that nothing in the test suite or the gate was capable of seeing.

The round-2 lint fix silently killed the guard it was protecting

1a275ebb rewired the elapsed measurement from the standard library's monotonic clock to harness.env().clock().monotonic(), to satisfy the time-via-env invariant. It compiled, the suite stayed green at 7/7, and the full gate passed 52 static checks.

The guard was dead. Harness::start installs Env::deterministic, whose ManualClock advances only when a test calls .advance(), and nothing here does. Both reads returned the same instant, so elapsed was permanently Duration::ZERO and the assertion had degraded to 0 < 5s. The .min to .max mutant that round 1 added this guard to kill was quietly alive again.

No gate could have caught this. A vacuous assertion passes, so a green suite and green static scans were both fully consistent with the defect, and there is no mutation lane in CI. Reading the harness is the only thing that finds it.

I also have to retract a claim I made in this PR's own description: the CAUGHT verdict I cited was measured against 63440c9f, before the clock swap. I then changed the guard's time source and kept citing the old result. A mutation verdict is evidence about one tree, and editing the guard invalidated it.

What changed

Real monotonic time, with the invariant-allow marker this repo already grants a timing harness. outbound_timing_probe.rs reached this conclusion first and its marker states my case verbatim: "the Clock seam has no monotonic elapsed and injecting one would measure the seam". The ceiling in invariant-lints.sh goes 2 to 3 to account for it.

And a structural fix rather than only a repair: the assertion now has a LOWER bound. An upper bound is satisfied by zero, so it cannot detect its own death: it passes when the clock stops, when the await is removed, when the measurement never starts. Against a target that never answers, a correctly bounded consultation cannot return materially faster than its bound. The floor is what makes the ceiling falsifiable.

The other two confirmed findings, both prose

  • The NTP rationale stated the direction backwards. I wrote that a step backwards would make the measured span EXCEED a budget. It makes it smaller; a forwards step inflates it. Corrected to name both directions and what each would do.
  • The const-assert doc was wrong by a factor of ten. It claimed the build breaks past "a quarter of the default", which is 2500. The assertion admits HANG_TIMEOUT_MS up to 250 and breaks at 251. The doc now states the real threshold and says the bound and the multiple are tuned together.

Re-verified on the final code, not on a superseded tree

  1. Suite green with the restored measurement and the new floor: 7/7.
  2. The .min to .max mutant: CAUGHT, took 10.00690525s, allowed 5s.
  3. Reverting to the frozen Env clock: caught by the new floor, which is the check that proves the guard can now detect the exact regression that just got past two review rounds.

@ELares
ELares merged commit dd8a152 into main Aug 22, 2026
15 checks passed
@ELares
ELares deleted the feat/112-sync-fixture branch August 22, 2026 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant