Python developer reviewing NumPy isclose argument order and reference-based tolerance checks on a computer screen.

Which Value Did NumPy Use as the Tolerance Reference?

Wed, Oct 14, 2026

Which Value Did NumPy Use as the Tolerance Reference?

np.isclose(7., 8., rtol=.125, atol=0) returns True. Reverse only the arguments, using np.isclose(8., 7., rtol=.125, atol=0), and the result is False. The numbers, their difference and the explicit tolerances have not changed. Neither has their shape. What changed is which value supplies the relative allowance. These are the first two results in the supplied twelve-case fixture, independently reproduced with the displayed driver.

That contrast is not evidence that NumPy is broken. It exposes a question a numerical release check must answer: which input is the approved reference? When the implementation puts the observation in that position, a successful function call can enforce the wrong acceptance policy.

This playbook investigates that boundary without modifying the observations. It preserves six coordinate identities, calculates each difference and allowance, and compares the elementwise mask with aggregate and assertion-based checks. Negative values, a zero reference and an explicit absolute floor make the limits visible. A separate comparison with Python’s math.isclose prevents an apparently convenient API substitution from silently changing the rule.

The laboratory uses small, finite CPU values rather than a model or benchmark. Its deliberately generous relative tolerance makes argument order easy to inspect; it is not a production recommendation. The practical outcome is a reviewable decision: repair reversed argument plumbing, accept only the bounded implementation under an approved policy, or hold when the reference, units or retained evidence cannot support a decision.

Declare the reference, units and acceptance policy

Before reading the gate, write down the meanings of its inputs. Observed means the values being assessed. Reference means the approved values against which those observations are assessed. Neither name is established by which array was loaded first, which file is older, or which variable already occupies the second argument.

For this fixture, both arrays use the same synthetic unit and the stable coordinate order p0 through p5. Position p2 always compares the observation assigned to p2 with its reference. No sorting, axis conversion or feature rearrangement is authorized. The reference is designated by the laboratory contract, not discovered from the numbers.

Set rtol=1/8, written as .125, and atol=0 for the principal experiment. The relative parameter is dimensionless; the absolute parameter must be expressed in the same units as the compared values. The corresponding 12.5% relative setting is intentionally conspicuous. Its usefulness for demonstration says nothing about an acceptable scientific error budget.

A release policy should identify the reference artifact and revision, coordinate order, units, tolerance values, and person authorized to approve them. It should also state whether every coordinate must pass and where individual failures remain available. Without that declaration, a maintainer can reproduce a Boolean but cannot determine whether it answers the intended question.

Treat approval as an input to testing, not a conclusion extracted from a passing test. For example, an old regression output may be the designated reference, but age alone does not establish that designation. Conversely, a newly reviewed reference may be authoritative even though it is newer than the observation.

For broader preparation, Refonte Learning’s numerical Python foundations provide surrounding learning context. This investigation stays narrower: approve the meaning of one comparison before trusting its outcome.

Read the allowance from the second argument

For finite inputs, the NumPy 2.3 isclose contract tests the following inequality. The second argument, b, supplies the reference magnitude; the absolute and relative terms are added.

difference = abs(observed - reference)

allowance  = atol + rtol * abs(reference)

accepted   = difference <= allowance

Apply it to observed 7 and reference 8. The difference is 1. With rtol=1/8 and atol=0, the allowance is 0 + (1/8 × 8) = 1. The inclusive boundary accepts the observation because 1 <= 1.

Now reverse the arguments. The difference remains 1, but the second argument is 7, so the allowance becomes 7/8, or .875. The comparison fails because 1 > .875. No mysterious numerical adjustment is required to explain either result. These small calculations also show exactly which term changed.

This is the central diagnostic for NumPy isclose asymmetry: inspect the source of the allowance, not just the distance between values. A log containing only difference=1 leaves out the evidence needed to distinguish the two decisions.

Keep directionality separate from equality

An acceptance relation answers an application question: is this observation acceptable relative to this reference under this policy? It does not assert that two distinct values have become equal, interchangeable identifiers or interchangeable sources of authority.

Directionality can therefore be intentional. A reviewed baseline can define the scale against which another result is judged. The implementation defect arises when the approved roles say one thing and the call order says another.

Keep those responsibilities separate during review. First establish which input is authoritative. Then inspect whether that input reaches NumPy’s second position. Calling both directions and choosing whichever passes would replace the approved rule with a different, unapproved rule. Calling both can be useful diagnostic evidence, but it is not permission to select a preferred verdict.

Run the twelve-case known-answer laboratory

Save the complete driver below as isclose_fixture.py in a writable disposable directory. Use CPython 3.13.5 and NumPy 2.3.5 for the stated reproduction. Its principal comparisons use ordinary CPU float64 values with matching one-dimensional vector shapes. N11 deliberately supplies invalid representations to test rejection. The driver makes no network request, loads no external dataset and performs no timing benchmark.

The supplied commissioning record reports PASS_12_CASES, starting at 2026-10-14T08:25:18.487634+00:00 and finishing at 2026-10-14T08:25:18.503702+00:00. Its recorded platform is Linux-6.18.44-x86_64-with-glibc2.41. Those are supplied laboratory observations, not a production incident.

An independent reproduction of the same driver returned PASS_12_CASES on CPython 3.13.5, NumPy 2.3.5 and the same platform. That execution started at 2026-10-14T12:13:45.378571+00:00 and finished at 2026-10-14T12:13:45.388240+00:00. Its JSON report agrees with all twelve case results and the six-coordinate evidence below. The timestamps identify executions; they are not performance evidence.

The unchanged source file used for that reproduction has this SHA-256, matching the supplied driver digest:

64b82ada9eb36d2672c8b8f471ed2f8a161ff3f3a4dc91899f2662523196e810

The code records its own file digest. Changes to source bytes, including line endings, produce a different identity and must accompany a new report. A matching digest identifies the driver; it does not approve a tolerance policy.

python isclose_fixture.py

"""Reference-oriented comparison on small, finite float64 vectors."""

import hashlib

import json

import math

import platform

import tempfile

from datetime import datetime, timezone

from fractions import Fraction

from pathlib import Path

import numpy as np

def require(ok, message):

    if not ok:

        raise RuntimeError(message)

def vector(values):

    return np.array(values, dtype=np.float64)

def compare(*, observed, reference, rtol, atol):

    for value in (observed, reference):

        if (type(value) is not np.ndarray or value.dtype != np.dtype("float64") or

                value.ndim != 1 or not value.size or not np.isfinite(value).all() or

                np.any(np.abs(value) > 1e6)):

            raise ValueError("Expected bounded finite float64 vector")

    if observed.shape != reference.shape:

        raise ValueError("Expected identical vector shape")

    if not (math.isfinite(rtol) and 0 <= rtol < 1 and math.isfinite(atol) and 0 <= atol <= 1e6):

        raise ValueError("Invalid tolerance policy")

    return np.isclose(observed, reference, rtol=rtol, atol=atol, equal_nan=False)

def rational_mask(a, b, rtol=Fraction(1, 8), atol=Fraction(0)):

    # Independent exact arithmetic for these authored binary-exact inputs only.

    return [abs(Fraction(x) - Fraction(y)) <= atol + rtol * abs(Fraction(y))

            for x, y in zip(a, b, strict=True)]

def main():

    destination = Path(tempfile.mkdtemp(prefix="isclose-", dir=Path(__file__).parent))

    report = {"revision": "isclose-v1", "status": "FAIL", "cases": [],

              "started_utc": datetime.now(timezone.utc).isoformat(),

              "python": platform.python_version(), "numpy": np.__version__,

              "platform": platform.platform(),

              "source_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest()}

    def record(identity, data, expected):

        row = {"id": identity, "status": "FAIL", "observed": data, "expected": expected}

        report["cases"].append(row)

        require(data == expected, identity + ": literal manifest mismatch")

        row["status"] = "PASS"

    def pair(a, b, **kw):

        return bool(np.isclose(a, b, **kw))

    try:

        record("N1_direction", [pair(7., 8., rtol=.125, atol=0),

                               pair(8., 7., rtol=.125, atol=0)], [True, False])

        a, b = [7., 8., -7., -8., .125, 0.], [8., 7., -8., -7., 0., 0.]

        literal = [True, False, True, False, False, True]

        mask = np.isclose(vector(a), vector(b), rtol=.125, atol=0).tolist()

        record("N2_independent_rational_oracle", [mask, rational_mask(a, b)], [literal, literal])

        record("N3_negative_orientation", [pair(-7., -8., rtol=.125, atol=0),

                                            pair(-8., -7., rtol=.125, atol=0)], [True, False])

        record("N4_near_zero_defaults", [pair(5e-9, 0.), pair(5e-9, 0., rtol=1e-5, atol=0)],

               [True, False])

        record("N5_explicit_absolute_floor", [pair(.125, 0., rtol=.125, atol=0),

                                               pair(.125, 0., rtol=.125, atol=.25)], [False, True])

        record("N6_allclose_reduction", [bool(np.allclose(a, b, rtol=.125, atol=0)),

                                          bool(np.allclose(b, a, rtol=.125, atol=0))], [False, False])

        outcome = []

        for actual, desired in [(7., 8.), (8., 7.)]:

            try:

                np.testing.assert_allclose(vector([actual]), vector([desired]),

                                           rtol=.125, atol=0, equal_nan=False, strict=True)

                outcome.append("PASS")

            except AssertionError:

                outcome.append("AssertionError")

        record("N7_assert_allclose_orientation", outcome, ["PASS", "AssertionError"])

        record("N8_math_isclose_uses_another_contract",

               [math.isclose(7., 8., rel_tol=.125, abs_tol=0),

                math.isclose(8., 7., rel_tol=.125, abs_tol=0)], [True, True])

        record("N9_not_transitive", [pair(7., 8., rtol=.125, atol=0),

                                     pair(8., 9., rtol=.125, atol=0),

                                     pair(7., 9., rtol=.125, atol=0)], [True, True, False])

        result = compare(observed=vector(a), reference=vector(b), rtol=.125, atol=0)

        record("N10_named_reference_boundary", result.tolist(), literal)

        controls = []

        inputs = [

            (vector([7.]), vector([[8.]]), .125, 0),

            (np.array([7], dtype=np.int64), vector([8.]), .125, 0),

            (vector([float("nan")]), vector([float("nan")]), .125, 0),

            (vector([7.]), vector([8.]), -.125, 0)]

        for observed, reference, rtol, atol in inputs:

            try:

                compare(observed=observed, reference=reference, rtol=rtol, atol=atol)

            except ValueError:

                controls.append("ValueError")

            else:

                controls.append("UNEXPECTED_ACCEPT")

        record("N11_admission_controls", controls, ["ValueError"] * 4)

        record("N12_sum_versus_max_tolerance", [pair(6.5, 8., rtol=.125, atol=1.),

                math.isclose(6.5, 8., rel_tol=.125, abs_tol=1.)], [True, False])

        report["vector_evidence"] = {"ids": ["p0", "p1", "p2", "p3", "p4", "p5"],

                                    "observed": a, "reference": b,

                                    "difference": np.abs(vector(a) - vector(b)).tolist(),

                                    "allowance": (.125 * np.abs(vector(b))).tolist()}

        require(len(report["cases"]) == len({r["id"] for r in report["cases"]}) == 12,

                "Incomplete case inventory")

        report["status"] = "PASS_12_CASES"

    except Exception as error:

        report["error"] = {"type": type(error).__name__, "message": str(error)}

        raise

    finally:

        report["finished_utc"] = datetime.now(timezone.utc).isoformat()

        path = destination / "results.json"

        path.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n")

        print(path)

if name == "__main__":

    main()

Each invocation creates a new isclose- directory beside the script and prints the path to results.json. Retain that directory rather than recycling a previous successful report. Inspect the reported interpreter, library version, source digest and twelve unique case IDs before comparing outcomes. The driver records versions but does not refuse to run under a different version, so an unexpected environment must not be described as this pinned reproduction.

The literal manifests are deliberate. N1 expects one directional pass and one failure. N2 expects the same six-coordinate mask from NumPy and independent rational arithmetic. N7 expects an assertion exception after reversal. N11 expects four admission errors. These are not failures to conceal; they are the outcomes that demonstrate the relevant boundaries.

The report begins in FAIL state and changes to PASS_12_CASES only after the case-count check. A recorded mismatch retains its failed row, records the exception and re-raises it. However, this is not a separately fault-injected reporting subsystem: failures before report initialization or during file writing are not proved recoverable. Retain console output and incomplete artifacts when execution stops; missing evidence is not a pass.

Use an independent oracle only within its proved domain

The Fraction calculation does not call np.isclose. For these authored inputs, it constructs exact rational differences and reference-scaled allowances, then checks them against a literal expected mask. The small integers and eighths used for the oracle comparison are binary-exact, and their relevant intermediate arithmetic is exact here.

That qualification matters. As the Python Fraction constructor documentation explains, constructing Fraction from a float preserves that float’s value. It does not recover an intended decimal measurement. Nor does exact rational arithmetic reproduce every rounding step of a general floating-point expression. The oracle therefore supports these chosen cases, not a universal proof for every float64 boundary.

N4 deliberately has a different purpose. Its 5e-9 input exposes what the documented default absolute tolerance admits near zero. It is neither a claim of exact decimal representation nor an extension of the rational oracle. Keep the diagnostic purpose attached to each case instead of treating every successful comparison as the same kind of evidence.

Keep the coordinate mask after the aggregate check

The principal arrays, in order p0 through p5, are observed [7, 8, -7, -8, .125, 0] and reference [8, 7, -8, -7, 0, 0]. Under .125 relative tolerance and zero absolute tolerance, their evidence is:

ID

Observed

Reference

Exact difference

Allowance

Mask

p0

7

8

1

1

True

p1

8

7

1

.875

False

p2

-7

-8

1

1

True

p3

-8

-7

1

.875

False

p4

.125

0

.125

0

False

p5

0

0

0

0

True

The resulting mask is [True, False, True, False, False, True]. N2 verifies it against both the rational oracle and the literal manifest. The report retains the IDs, inputs, differences and allowances together, making each decision inspectable rather than merely counting successful coordinates.

NumPy’s allclose contract applies its reference-oriented tolerance across the compared elements and returns one Boolean. For these matched vectors, it answers whether every coordinate meets the selected rule.

N6 returns False in both directions. That apparent agreement does not establish identical elementwise behavior. Applying the equation after reversal gives allowances [.875, 1, .875, 1, .015625, 0] and the derived mask [False, True, False, True, False, True]. The first four coordinate verdicts change; the aggregate remains false.

Even the number of passing coordinates is unchanged: three in each direction. Neither the aggregate nor the pass count can tell a reviewer that p0 and p1 exchanged acceptance status. The reversed mask here is an arithmetic derivation; N6 itself records only its two aggregate results.

Preserve the mask before reduction, and retain its coordinate mapping beside it. A release summary may display one status, but an investigation needs the first divergence, its original values and the allowance actually applied. Do not reconstruct identity later from a sorted list of failures.

Test signs and a zero reference explicitly

N3 repeats the directional pair with negative values. Observed -7 against reference -8 has difference 1 and allowance 1, so it passes. Observed -8 against reference -7 has the same difference but allowance .875, so it fails. These results match the positive pair because the calculation uses reference magnitude, not a signed allowance.

This control prevents an incomplete repair that appears correct only for positive inputs. In the six-coordinate ledger, p2 and p3 are separate identities, not duplicates to discard because their absolute differences resemble p0 and p1.

N5 isolates zero. Comparing observed .125 with reference 0, the relative contribution is .125 × 0 = 0. With atol=0, the allowance is zero and the observation fails. With an explicitly selected atol=.25, the allowance becomes .25 and the observation passes.

Nothing in that calculation divides by the reference. Zero is relevant because it contributes no relative allowance, not because the gate encounters a zero denominator. Rewriting the check as a percentage division would introduce a different implementation and is unnecessary for this investigation.

A relative tolerance cannot authorize its own absolute floor

The absolute allowance needs an independent domain justification. Ask what discrepancy is negligible in the declared units, who approves that threshold, and whether the same threshold applies to all admitted coordinates. The laboratory’s .25 floor demonstrates a policy effect; it does not recommend that floor for scientific measurements.

A zero reference should therefore trigger inspection of the approved absolute policy, not an automatic tolerance increase. When no authority exists for a nonzero floor, retain the failing observation and hold the acceptance decision rather than inventing permission.

This is distinct from a separate paired-loss shape contract. Here the pairings are already fixed. Changing an axis, regrouping values or repairing shapes would not answer whether an absolute discrepancy is authorized. Keep the coordinate identity intact while reviewing the allowance.

Expose what the defaults admit near zero

The versioned NumPy 2.3 documentation on defaults gives np.isclose defaults of rtol=1e-5, atol=1e-8 and equal_nan=False, and warns that the default absolute tolerance needs particular care for small reference magnitudes.

N4 deliberately leaves the tolerances unspecified in its first call: observed 5e-9 is compared with reference 0. The reported result is True. The second call explicitly supplies rtol=1e-5 and atol=0; it returns False.

With a zero reference, the relative term contributes nothing in either call. The first comparison therefore has an absolute allowance of 1e-8, while the second has zero. This is a policy difference large enough to explain the result without claiming that the decimal literal has an exact binary representation.

Do not label one outcome universally correct. In a hypothetical signal-detection workflow, a nonzero quantity at this scale might be scientifically meaningful. In another application, a residual of that size might be intentionally negligible. Those applications need different evidence and possibly different approved floors. The library cannot infer which interpretation applies from the magnitude alone.

The operational repair is to make the chosen tolerance explicit and traceable. Search the gate and its surrounding helpers for omitted arguments. Record the effective settings at the final comparison, not merely the values a configuration file was intended to provide. N4 is the intentional default diagnostic; it is not the template for the repaired acceptance boundary.

Also distinguish a near-zero reference from an unknown value. This fixture contains a real numerical zero with a declared role. It does not use zero as a substitute for missing evidence, nor does it authorize filling absent references with zero before comparison.

When a reviewer cannot establish whether a small residual should matter, the appropriate result is HOLD on policy approval. Changing atol until the current test becomes green would hide the unresolved requirement instead of resolving it.

Pin the actual and desired roles in assertions

N7 makes the assertion contract explicit: actual receives the observation and desired receives the reference. The NumPy 2.3 assert_allclose documentation defines the allowance in terms of abs(desired). It also documents defaults different from isclose: rtol=1e-7, atol=0 and equal_nan=True. The fixture overrides all three relevant policy settings.

np.testing.assert_allclose(

    vector([actual]), vector([desired]),

    rtol=.125, atol=0, equal_nan=False, strict=True

)

With actual 7 and desired 8, N7 records PASS. Reversal produces the expected AssertionError. Both arguments remain one-element float64 arrays, so the negative result is the numerical orientation control, not a shape or dtype mismatch.

Catch that expected exception only inside the case designed to verify it. The driver converts the exception into an explicit outcome string and compares the two outcomes with ['PASS', 'AssertionError']. An unexpected exception elsewhere still fails the laboratory. Silently swallowing every assertion error would destroy the distinction between an expected negative control and a broken gate.

The documented strict=True option requires matching shape and dtype and disables the special scalar handling described by the API. It was introduced in NumPy 2.0, not as a new NumPy 2.3 feature.

Do not use shape checks as a substitute for semantic roles

The supplied vectors demonstrate why structural checks are supportive rather than authoritative. Swapping two arrays with the same shape and dtype leaves those checks satisfied. A structural guard cannot determine which file the domain owner approved as the baseline.

The neighboring question of feature identity before numerical comparison must already be settled here. This experiment does not fit a model, reorder features or infer missing labels. It asks which already-identified array supplies the tolerance scale.

During review, trace actual and desired back to their origins. Confirm the assertion receives the same approved roles and explicit tolerance values as the runtime gate. Agreement on an API name is insufficient when two callers populate its parameters differently. Require the directional negative control to remain sensitive after any refactoring.

Compare math.isclose without silently changing the contract

Python’s math.isclose uses a symmetric relative scale and combines tolerance terms with a maximum rather than addition. The Python 3.13 math.isclose documentation states this finite-value test. The documentation branch is not evidence of the executed interpreter’s patch version, which the run report records separately.

abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

N8 supplies rel_tol=.125 and abs_tol=0 explicitly. For 7 and 8, the larger magnitude is 8 in either order, giving allowance 1. Both directions return True. Symmetry follows from the selected scale; it is not evidence that the reversed NumPy gate has been correctly repaired.

N12 separates another distinction that the first pair cannot expose. Compare 6.5 with 8, keeping relative tolerance .125 but setting the absolute tolerance to 1. The difference is 1.5. Both APIs use a magnitude of 8 for their relative term in this ordering, so each relative contribution is 1.

NumPy adds the absolute and relative contributions: 1 + 1 = 2, admitting 1.5. Python takes their maximum: max(1, 1) = 1, rejecting 1.5. The literal expected result is therefore [True, False], and both recorded executions agree.

Case

NumPy allowance

Python allowance

NumPy / Python result

7 versus 8; absolute zero

1

1

True / True

8 versus 7; absolute zero

.875

1

False / True

6.5 versus 8; absolute one

2

1

True / False

A substitution changes more than spelling or parameter names. It can change both orientation and the way two forms of tolerance interact. Approve that policy change separately, with cases that distinguish its effects.

For a genuinely symmetric requirement, choose and document a symmetric contract deliberately. For the reference-oriented requirement being repaired here, keep the approved equation and restore its argument roles. Agreement on one comfortable pair is not evidence that two APIs enforce the same boundary.

Demonstrate why a chain of close pairs is insufficient

N9 compares three fixed pairs under .125 relative tolerance and zero absolute tolerance. The expected sequence is [True, True, False].

For observed 7 against reference 8, difference 1 meets allowance 1. For observed 8 against reference 9, difference 1 meets allowance 9/8, or 1.125. But observed 7 against reference 9 differs by 2, exceeding the same 1.125 allowance.

The two successful links therefore do not establish the third comparison. This is an arithmetic counterexample to transitivity for the stated relation, not a failure of the implementation. Each call evaluates its own pair under its own reference-scaled allowance.

In a release review, that means evidence against an intermediate result cannot automatically replace evidence against the approved reference. A hypothetical revision accepted against its predecessor has not thereby been shown acceptable against every earlier baseline. The missing direct comparison remains missing, regardless of how many preceding checks were green.

Retain the reference identity with each result so reviewers can see which relationship was actually tested. A report that says only “close to the previous result” leaves the endpoint requirement unresolved.

Do not repair the values to repair a comparison

Changing 7, 8 or 9 would remove the counterexample instead of explaining it. This laboratory preserves the inputs and asks whether the implementation matches the approved gate. It does not round observations, replace references with averaged values or rewrite measurements to recover a pass.

Refonte Learning’s discussion of step rounding as a different numerical requirement concerns a separate contract. No rounding step is authorized by this comparison policy, and importing one would require its own requirements and evidence.

The appropriate response to a failed direct comparison is to retain the result, inspect the reference and tolerance authority, and repair the implementation only when it violates that authority. A chain of earlier passes cannot supply permission to alter either the data or the acceptance threshold.

Make reference orientation explicit at the call boundary

The driver’s compare function uses keyword-only arguments: observed, reference, rtol and atol. A caller must name the roles, and the implementation visibly forwards the reference to NumPy’s second argument. N10 confirms that this boundary preserves the literal six-coordinate mask.

The admission checks are intentionally narrow. Both inputs must be ordinary np.ndarray objects with float64 dtype, one dimension, at least one element, finite values and magnitudes no greater than 1e6. Their shapes must match. For the scalar numerical tolerances used here, the checks require finite settings with 0 <= rtol < 1 and 0 <= atol <= 1e6.

Those bounds define this wrapper’s scope; they are not universal NumPy limits or scientific approval criteria. A tolerance can satisfy these numerical limits and still be unauthorized for the application. Likewise, naming an array reference does not authenticate its origin.

N11 executes four rejection subcontrols: a two-dimensional reference, an integer observation array, NaN inputs and a negative relative tolerance. Each must raise ValueError. These four cases do not exhaust every guard. Empty arrays, unequal one-dimensional lengths, excessive magnitudes, infinity and malformed tolerance objects are not separately exercised by this driver. Do not report code inspection as additional executed coverage.

The wrapper also deliberately avoids implicit array conversion. Its vector helper constructs authored fixture inputs; compare itself rejects unsupported input representations rather than quietly normalizing them. General-purpose tolerance-object validation and coercion are outside the demonstrated contract.

Use the named boundary to make review easier, then trace each supplied value back to the approved manifest. A programmer can still write observed=baseline and reference=candidate. The directional known-answer test detects the resulting equation change only when the actual call path is covered. Names improve visibility; they do not replace provenance or integration evidence.

Reconcile all twelve decisions and their evidence

Read this inventory as a comparison between predetermined outcomes and recorded behavior. In the table, T means True, F means False, and M means [T,F,T,F,F,T] in coordinate order p0 through p5. “Observed” describes the independent reproduction; every entry also agrees with the supplied commissioning results.

Case and policy

Expected result

Observed result

Interpretation

N1: positive direction

T, F

T, F

Reversal changes the allowance.

N2: NumPy / rational oracle

M / M

M / M

Independent arithmetic and literals agree.

N3: negative direction

T, F

T, F

Reference magnitude preserves the contrast.

N4: defaults / zero absolute floor

T, F

T, F

Near-zero policy changes admission.

N5: absolute floor 0 / .25

F, T

F, T

A positive floor admits the authored discrepancy.

N6: allclose forward / reverse

F, F

F, F

Aggregate agreement hides coordinate changes.

N7: actual / desired reversal

PASS, AssertionError

PASS, AssertionError

Expected assertion failure proves sensitivity.

N8: math.isclose both directions

T, T

T, T

Symmetric scale follows another contract.

N9: 7→8, 8→9, 7→9

T, T, F

T, T, F

Accepted links do not establish endpoints.

N10: named-reference wrapper

M

M

Boundary preserves the approved orientation.

N11: 2D / int64 / NaN / negative rtol

Four ValueErrors

Four ValueErrors

These four admissions are rejected.

N12: NumPy / math, absolute one

T, F

T, F

Additive and maximum allowances differ.

A case passes when its observed behavior matches the literal expectation. That includes an expected exception or numerical rejection. Consequently, PASS_12_CASES does not mean all compared observations were acceptable: the main vector contains three rejected coordinates.

Keep that distinction in release reporting. The laboratory can qualify a bounded implementation while correctly rejecting data. It cannot approve the chosen units, the authority of an operational baseline, or the suitability of .125 merely because all twelve case records say PASS.

Recover decisions made under a reversed gate

When review establishes that an operational gate reversed approved roles, preserve the affected evidence before recomputing anything. Retain the original observed and reference arrays, their coordinate mapping, units, tolerance values, reference revision, gate revision and recorded outcome. Keep the discovery and corrected evaluation linked without overwriting the historical record.

First determine which executions actually used the reversed implementation. A suspected code path is not proof that every past decision traversed it. Bound the affected interval using trustworthy version and execution records, and leave unresolved records explicitly unresolved.

Next, recompute only those decisions whose inputs and policy can be reconstructed reliably. Use the repaired implementation with the original approved roles and tolerances. Record the old and corrected coordinate masks, not just whether the aggregate changed. N6 demonstrates why an unchanged aggregate cannot establish that the reversal was harmless.

Review changed verdicts with the policy owner. Correcting argument order may turn some passes into failures and some failures into passes; the fixture’s first four coordinates show both possibilities. Neither direction authorizes modifying the original observation or silently replacing a historical approval.

Separate implementation repair from policy approval

REPAIR means the implementation reverses the approved observed/reference roles. Restore the argument mapping while preserving the authorized equation and settings, then retain evidence that the directional control detects the old behavior and the repaired boundary produces the expected mask.

ACCEPT_BOUNDED means the named boundary matches the independent known-answer evidence, its admitted domain is understood, and the reference role, units and tolerances have been approved. It describes that bounded qualification, not a blanket guarantee for arbitrary numerical inputs.

HOLD applies when reference authority, units, an absolute floor or retained inputs cannot support the decision. Hold also covers incomplete or contradictory qualification evidence that has not been resolved.

Do not select tolerance values by searching for those that admit the desired outcome. A policy revision may be legitimate, but it needs its own rationale and approval. It must remain distinguishable from correcting an implementation that never followed the existing policy.

Assign tolerance ownership and regression triggers

Give the domain owner responsibility for approving the reference and numerical allowances. Give the maintainer responsibility for correct data provenance and argument plumbing. Give QA responsibility for retaining the known-answer cases, negative controls, environment identity and reports. These are proposed review responsibilities, not claims that a particular organization already follows them.

The separation resolves a common approval ambiguity. A maintainer can show that reference reaches the correct parameter without being authorized to decide what error is scientifically negligible. A domain owner can approve a threshold without demonstrating that every call site uses it. QA should require both pieces of evidence rather than treating either signature as sufficient.

For surrounding practice, owning repeatable numerical regression evidence connects this narrow laboratory to evidence-bearing automation. Here the useful artifact is not simply a green job: it is the retained relationship among inputs, policy, source revision and coordinate decisions.

Revalidate when a change affects API selection, supplied or inherited defaults, dtype, units, coordinate masks, missingness handling or vector shape. A dependency update also deserves comparison against the retained known answers. Revalidation means checking the relevant contract, not assuming every change necessarily produces a different result.

Changing to another dtype or admitting previously rejected values extends the domain. The twelve authored CPU cases do not certify that extension. Add evidence appropriate to the new boundary rather than attaching the old PASS_12_CASES label to a broader implementation.

Keep report completeness in the release criteria. Require the expected case inventory, source digest and environment details, and preserve failed runs alongside successful ones. The driver’s reporting paths have not been exhaustively fault-injected, so a missing report must remain missing evidence rather than being interpreted as numerical success.

Finally, distinguish tolerance qualification from model quality. This fixture evaluates no model, estimates no predictive accuracy and measures no production performance. It establishes whether a particular comparison boundary follows a stated numerical policy on its authored cases. The release owner still needs the application-specific evidence that makes that policy appropriate.

Build numerical judgement through structured practice

A useful practice exercise is to hand a reviewer the six-coordinate table without its mask and ask for each allowance before running the driver. Then ask which evidence would justify the tolerance, what reversal changes, and why the aggregate cannot explain the individual decisions. The goal is not memorizing a surprising API result; it is separating arithmetic, implementation and authority.

For structured foundations, Refonte Learning’s Data Science & AI programme lists Python data science, statistical modelling and applied projects, with NumPy named in its tools FAQ. Check the current syllabus for any specialist floating-point or tolerance-testing coverage; the programme page does not establish that this exact laboratory is taught.

In the next numerical review, preserve the values, name the reference and calculate its allowance. Qualify that role before accepting the closeness result, not after a Boolean has already become a release decision.