Skip to content

docs+test: replace exact-identity gate with ULP + rank-stability tolerance - #504

Merged
cdeust merged 4 commits into
mainfrom
fix/numeric-equivalence-tolerance
Sep 8, 2026
Merged

docs+test: replace exact-identity gate with ULP + rank-stability tolerance#504
cdeust merged 4 commits into
mainfrom
fix/numeric-equivalence-tolerance

Conversation

@cdeust

@cdeust cdeust commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Summary

Captures, in a pushable form, an analysis that was done on a machine that cannot push to this repo: docs/provenance/green-w3-2-encoding-identity.md (PR #495) recorded "The requested contract is exact score identity, not a numeric tolerance" and "No tolerance has been adopted." That decision is retracted here — not for lack of evidence, but because it was evaluated against the wrong predicate.

IEEE 754 float32 addition/multiplication is not associative, so a batched matmul reduces its terms in a different order than N independent scalar calls and will not, in general, reproduce the same bit pattern — even when both results are correct. A gate specified as exact bitwise equality between a scalar path and a batched path is therefore unsatisfiable by construction: no batched implementation can ever pass it, regardless of correctness, and it will reject the same optimization forever.

The tell that this is what actually happened: float32 machine epsilon is 2**-23 = 1.1920928955078125e-07. Every delta PR #495 and PR #497 recorded as a rejection is within ~1.4x of exactly this number — PR #495's score delta equals it, to every reported digit:

Source Recorded delta In float32 ULP
PR #495 normalized-vector delta 1.6391277313232422e-07 ~1.375
PR #495 score delta 1.1920928955078125e-07 exactly 1.000
PR #497 vector delta 1.0617077350616455e-07 ~0.891
PR #497 lessons delta 9.313225746154785e-08 ~0.781
PR #497 compression delta 1.3969838619232178e-07 ~1.172

A genuine computational defect does not track machine epsilon this tightly across five unrelated code paths on two different PRs.

Changes

  • benchmarks/lib/numeric_equivalence.pyvectors_equivalent() (ULP tolerance per component, DEFAULT_MAX_ULP=4, ~3x headroom over the largest observed delta) and rank_stable() (the criterion that actually matters for a write-gate decision or retrieval ordering: a score shift of a few ULP must not flip which candidate wins unless the two were already tied within tolerance on the scalar path — in which case either order was already an acceptable outcome).
  • tests_py/benchmarks/test_numeric_equivalence.py — reproduces the exact deltas from the table above and confirms both functions now pass them, while still rejecting a real regression (tested at 0.01, four orders of magnitude larger than any measured rounding delta).
  • docs/provenance/numeric-equivalence-tolerance.md — the retraction, the sourced table, and what remains open (see below).

What this does NOT do

It does not restore the batched code paths PR #495 (60e5646b, "batch normalized neighbors and reuse unchanged merge vectors") or PR #497 reverted. This session has no torch/sentence-transformers available to re-run either PR's own harness against the new gate. Applying the new functions to the already-recorded deltas above says they'd now pass, but a maintainer with the pinned MiniLM encoder available should re-run each PR's harness (cited in the new doc) before restoring either batched path, rather than trusting a transcription of numbers already in a closed PR body.

Test plan

  • ruff check / ruff format --check on both new Python files — clean.

  • python scripts/check_craftsmanship.py benchmarks/lib/numeric_equivalence.pyCraftsmanship gate: OK.

  • ast.parse() on both files — OK.

  • Manually executed every function in numeric_equivalence.py against the exact PR perf(remember): reuse embeddings for identical merge text #495/perf(embeddings): batch codebase imports and preserve cache contexts #497 deltas outside pytest (no pytest binary available in this sandbox) — matches every assertion in the committed test file.

  • Did not run the full pytest suite in this sandbox (no numpy/torch installed here — benchmarks/lib/__init__.py eagerly imports numpy via embedding_engine.py, by existing design, since numpy is a hard mcp_server dependency in the real dev environment). A maintainer should run pytest tests_py/benchmarks/test_numeric_equivalence.py once to confirm collection.

  • All existing tests pass. (new file only; not run in this sandbox — see above)

  • New tests added for new behavior.

  • Manual verification of any UI / CLI / MCP-tool behavior changes. (not applicable — no runtime code path changed)

Audit notes

Coding-standards compliance

  • §2.2 N/A — no layer-dependency code touched (new module lives in benchmarks/lib/, not a layered mcp_server/ package).
  • §4.1 No file > 500 lines (126 lines).
  • §4.4 N/A.
  • §7 Local reasoning preserved.
  • §8 Every numeric constant sourced: FLOAT32_ULP to IEEE 754 binary32; DEFAULT_MAX_ULP to the measured deltas in the table above, both in the module docstring and the doc.
  • §9 No dead code.

Breaking changes

None. Purely additive (new module + doc), touches no existing code path.

Reviewer checklist

  • CHANGELOG.md — not updated; this is an unreleased internal methodology doc + utility with no user-facing behavior change yet (the actual batching restoration, if a maintainer validates it, is the change that should carry a CHANGELOG entry).
  • Documentation updated (docs/provenance/numeric-equivalence-tolerance.md).
  • No secrets / credentials / PII in the diff.
  • CI passes on the latest commit — pending.

🤖 Generated with Claude Code

https://claude.ai/code/session_01StMBvNd7eVJGtpnC2zNsx1


Generated by Claude Code

…rance

Retracts docs/provenance/green-w3-2-encoding-identity.md's "no tolerance
adopted" decision (PR #495). That gate required bitwise-exact equality
between a scalar-path and a batched-path float32 computation, which no
batched implementation can pass by construction: IEEE 754 float32
addition/multiplication isn't associative, so a batched matmul reduces in
a different element order than N scalar calls and won't reproduce the
same bit pattern even when both results are correct.

Evidence this is what happened, not a coincidence: every delta PR #495
and PR #497 recorded as a rejection (1.64e-7, 1.19e-7, 1.06e-7, 9.31e-8,
1.40e-7) is within ~1.4x of float32 machine epsilon (2**-23 =
1.1920928955078125e-07) — the PR #495 score delta equals it exactly.

Adds benchmarks/lib/numeric_equivalence.py: vectors_equivalent() (ULP
tolerance per component) and rank_stable() (a score shift must not flip
which candidate wins unless they were already tied within tolerance).
Both are exercised in tests_py/benchmarks/test_numeric_equivalence.py
against the exact deltas above, reproduced from the two PR bodies.

Does not itself restore the batched code paths PR #495/#497 reverted —
this session had no torch/sentence-transformers available to re-run
either PR's own harness against the new gate. See the new doc's closing
section for what a maintainer with the pinned model needs to re-check
before doing that.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StMBvNd7eVJGtpnC2zNsx1
The craftsmanship gate's unsourced-constant rule only recognizes a
# source: comment sitting directly on, or in a contiguous comment run
immediately above, the assignment line it covers — a comment shared
across a block of several assignments only satisfies the first one.
PR_495_SCORE_DELTA, PR_497_LESSONS_DELTA and PR_497_COMPRESSION_DELTA
each sat below a sibling assignment instead of a comment line, so the
gate flagged them (CI run 34209985343, Craftsmanship Gate). Reproduced
locally with `python scripts/check_craftsmanship.py --base origin/main`
and confirmed green after giving each constant its own source line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StMBvNd7eVJGtpnC2zNsx1

cdeust commented Sep 8, 2026

Copy link
Copy Markdown
Owner Author

CI: Validate MCP host configurations — not this PR's, re-run budget spent

This diff touches only benchmarks/lib/, tests_py/benchmarks/, and docs/provenance/ — nothing under tests_js/mcp-host-clis/, .github/workflows/ci.yml, or any MCP host config path this job exercises.

The job (.github/workflows/ci.yml mcp-host-config) has timeout-minutes: 3, sourced to a measured max of 61s (run 33951959734, 2026-09-05). On this PR's head (57979ebc) it has now hit that timeout twice in a row:

  • Attempt 1 (run 34210128951): all steps reported success but the job's overall conclusion was cancelled — a GitHub Actions API inconsistency, not a content failure.
  • Attempt 2 (same run, after I re-ran the failed jobs once): Validate Claude, Gemini, and Codex configuration parsing itself was cancelled ~2.5min into the step, consistent with the 3-minute job timeout — well past the ~61s this timeout was sized for.

Every other job on this head is green (Lint, Craftsmanship Gate, Type Check, all 5 Python test matrices, Windows/SQLite, Docker Smoke, Build Package, Release dependency set). I've already used the one re-run this failure mode is owed; a second silent re-run isn't warranted. Flagging here rather than re-running blind: if this timeout keeps tripping on unrelated PRs, timeout-minutes: 3 may need headroom above its 2026-09-05 measurement, or the npm ci/CLI-install step it covers has gotten slower (registry latency, larger pinned packages) since that measurement — a maintainer with visibility across recent runs is better placed to tell which.


Generated by Claude Code

cdeust commented Sep 8, 2026

Copy link
Copy Markdown
Owner Author

(Attribution addendum — omitted from the comment above by mistake.)


Generated by Claude Code

Brings in #503 (floor check non-blocking + --no-regression gate), which
this PR's base moved to. No file overlap between the two changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StMBvNd7eVJGtpnC2zNsx1

cdeust commented Sep 8, 2026

Copy link
Copy Markdown
Owner Author

Correction — mon commentaire précédent était faux, et sur le fond et sur la posture.

J'y écrivais « not this PR's, re-run budget spent » et j'attribuais le timeout à de la latence de registre npm. Les deux sont faux, et le cadrage lui-même l'était : une CI rouge sur une PR n'est pas un problème de CI, c'est le code qui ne passe pas la CI. « Pre-existing » est exactement le refus que les règles de ce dépôt nomment comme violation de contrat. J'aurais dû lire les logs avant de plaider.

Ce que les logs disent (run 34210128951 job 102009142706) :

npm ci                                   21 s
claude plugin validate .                 ~1 s
gemini extensions validate .             ~1 s
codex plugin add / mcp list              ~4 s
PASS codex-cli/lean: initialize + discovery + memory_stats (10 tools, 179.86s)

Le coût n'est pas la validation de config : c'est la dernière étape, scripts/verify_mcp_hosts.py, qui démarre le plugin via uvx contre un cache uv volontairement froid (UV_CACHE_DIR/UV_TOOL_DIR sous RUNNER_TEMP, --allow-bootstrap-network) — donc un resolve + build réseau complet à chaque run.

Deux échantillons, même PR, mêmes assertions, tous deux PASS :

Run Job Bootstrap Job total
34217620888 102033099129 23,98 s 52 s
34210128951 102009142706 179,86 s 194 s

Le run à 179,86 s a passé ses assertions et a été tué quand même, à 194 s, par le plafond de 180 s. timeout-minutes: 3 tombe à l'intérieur de la plage d'une exécution légitime — l'ancien ceil(2 * 61 / 60) était une marge 2× calculée sur un échantillon qui n'avait jamais vu la queue réseau.

Correctif dans #505 : timeout-minutes: 37, soit ceil(2 * 194 / 60) par la convention du dépôt, avec les deux mesures citées en # source:. Le cache froid n'est pas aplani : c'est le chemin qu'un nouvel utilisateur subit, donc c'est précisément ce que le job doit tester.


Generated by Claude Code

Brings in #505 (mcp-host-config timeout sized to its measured tail), so
this PR's CI runs under a bound that no longer decides on network luck.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01StMBvNd7eVJGtpnC2zNsx1
@cdeust
cdeust marked this pull request as ready for review September 8, 2026 12:25
@cdeust
cdeust merged commit 97442bc into main Sep 8, 2026
28 checks passed
@cdeust
cdeust deleted the fix/numeric-equivalence-tolerance branch September 8, 2026 16:01
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