|
| 1 | +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. |
| 2 | +# All rights reserved. |
| 3 | +# SPDX-License-Identifier: Apache-2.0 |
| 4 | + |
| 5 | +"""T1.32g part 2d, fix 3: a re-recorded reference line is the one a move |
| 6 | +is judged on. |
| 7 | +
|
| 8 | +Written by the package's independent test author, after the subagent's |
| 9 | +second review of part 2d (P3-1). The comparator relaxes from the |
| 10 | +candidate's reference line; ``ratchet.py``'s ``moves`` judged the stop |
| 11 | +and the outcome an entry's ``old`` must state on the checkpoint's. The |
| 12 | +rule (lane 1b's 260ffd60): where this change records a case's reference |
| 13 | +line again, the stop and that outcome are the new line's, and only this |
| 14 | +change's entries count; without a re-record nothing changes. |
| 15 | +
|
| 16 | +The seed (the subagent's probe), on ``tests/test_t132g_later_stage.py``'s |
| 17 | +real fixtures: at the checkpoint, the hugeint case is admitted with the |
| 18 | +core's success baselines held, its reference refusing at materialize; |
| 19 | +the change records the reference again refusing at from_source (an |
| 20 | +owner's entry naming it on python-ref), and python-core's public schema |
| 21 | +is tampered. Relaxed from from_source, the schema is past the stop and |
| 22 | +the tamper passes; held to the reference, it fails ``schema``. So: |
| 23 | +
|
| 24 | +- an entry whose ``old`` is the checkpoint's stale outcome does not relax |
| 25 | + (the tamper fails); |
| 26 | +- an entry whose ``old`` is the new line's outcome relaxes (clean); |
| 27 | +- the same entry at the checkpoint, not this change's, does not relax; |
| 28 | +- with no re-record, an entry from the reference's own outcome relaxes |
| 29 | + from materialize, where the schema is still held: the tamper fails. |
| 30 | +
|
| 31 | +Gating (``contract/tests/t132g_gate.py``): none of these is pending; each |
| 32 | +passed when written. |
| 33 | +""" |
| 34 | + |
| 35 | +from __future__ import annotations |
| 36 | + |
| 37 | +import importlib.util |
| 38 | +import sys |
| 39 | +from pathlib import Path |
| 40 | +from types import ModuleType |
| 41 | +from typing import Any |
| 42 | + |
| 43 | +ROOT = Path(__file__).resolve().parents[1] |
| 44 | + |
| 45 | + |
| 46 | +def _module(name: str, path: Path) -> ModuleType: |
| 47 | + if name not in sys.modules: |
| 48 | + spec = importlib.util.spec_from_file_location(name, path) |
| 49 | + assert spec is not None and spec.loader is not None |
| 50 | + module = importlib.util.module_from_spec(spec) |
| 51 | + sys.modules[name] = module |
| 52 | + spec.loader.exec_module(module) |
| 53 | + return sys.modules[name] |
| 54 | + |
| 55 | + |
| 56 | +moves = _module( |
| 57 | + 't132g_later_stage_moves_tests', |
| 58 | + ROOT / 'tests/test_t132g_later_stage_moves.py', |
| 59 | +) |
| 60 | +later = moves.later |
| 61 | + |
| 62 | +origin, repo = moves.origin, moves.repo |
| 63 | +HUGEINT, CORES, WHERE = moves.HUGEINT, moves.CORES, moves.WHERE |
| 64 | +entry, item, of, has = moves.entry, moves.item, moves.of, moves.has |
| 65 | +_edits, with_entry = moves._edits, moves.with_entry |
| 66 | +admitted, holding_the_core = moves.admitted, moves.holding_the_core |
| 67 | +set_reference, _re_recorded = moves.set_reference, moves._re_recorded |
| 68 | +REFERENCE_TEXT = moves.REFERENCE_TEXT |
| 69 | + |
| 70 | +#: The reference recorded again, refusing at from_source. |
| 71 | +NEW_TEXT = 'refusal INVALID_REQUEST at from_source (ValueError)' |
| 72 | +NEW_HOST_TEXT = 'refusal INVALID_REQUEST' |
| 73 | + |
| 74 | + |
| 75 | +def _refusal_at_from_source() -> dict[str, Any]: |
| 76 | + line: dict[str, Any] = moves._refusal_reference('from_source') |
| 77 | + return line |
| 78 | + |
| 79 | + |
| 80 | +def _tampered(found: Any, cases: dict[str, Any]) -> None: |
| 81 | + r"""python-core's public schema changed: evidence of from_source's end, |
| 82 | + which a reference refusing at materialize produced and one refusing |
| 83 | + at from_source did not.""" |
| 84 | + table = found['python-core'][HUGEINT]['public']['schema']['tables'][0] |
| 85 | + table['duplicate_keys'] += 7 |
| 86 | + |
| 87 | + |
| 88 | +def _move(old: str, host_old: str, **fields: Any) -> dict[str, Any]: |
| 89 | + return entry( |
| 90 | + item(HUGEINT, 'python-core') | {'old': old}, |
| 91 | + item(HUGEINT, 'rust-host') | {'old': host_old}, |
| 92 | + **fields, |
| 93 | + ) |
| 94 | + |
| 95 | + |
| 96 | +def _compared( |
| 97 | + r: Path, |
| 98 | + tmp: Path, |
| 99 | + in_change: Any, |
| 100 | + at_checkpoint: Any = None, |
| 101 | + re_recorded: bool = True, |
| 102 | +) -> list[tuple[str | None, str]]: |
| 103 | + refusal = _refusal_at_from_source() |
| 104 | + |
| 105 | + def change(found: Any, cases: dict[str, Any]) -> None: |
| 106 | + if re_recorded: |
| 107 | + moves._expecting(refusal)(found, cases) |
| 108 | + _tampered(found, cases) |
| 109 | + |
| 110 | + report = moves.compared( |
| 111 | + r, |
| 112 | + tmp, |
| 113 | + at_checkpoint=_edits( |
| 114 | + admitted(HUGEINT), holding_the_core(HUGEINT), at_checkpoint |
| 115 | + ), |
| 116 | + in_change=_edits( |
| 117 | + set_reference(HUGEINT, refusal) if re_recorded else None, |
| 118 | + with_entry(_re_recorded(REFERENCE_TEXT, NEW_TEXT)) |
| 119 | + if re_recorded |
| 120 | + else None, |
| 121 | + in_change, |
| 122 | + ), |
| 123 | + reference=refusal if re_recorded else None, |
| 124 | + change=change, |
| 125 | + ) |
| 126 | + found: list[tuple[str | None, str]] = of(report, HUGEINT) |
| 127 | + return found |
| 128 | + |
| 129 | + |
| 130 | +def test_an_entry_from_the_stale_checkpoint_outcome_does_not_relax( |
| 131 | + repo: Path, tmp_path: Path |
| 132 | +) -> None: |
| 133 | + found = _compared( |
| 134 | + repo, |
| 135 | + tmp_path, |
| 136 | + with_entry(_move(REFERENCE_TEXT, 'refusal INTERNAL_ERROR')), |
| 137 | + ) |
| 138 | + assert has(found, 'schema', WHERE), found |
| 139 | + |
| 140 | + |
| 141 | +def test_an_entry_from_the_new_line_s_outcome_relaxes( |
| 142 | + repo: Path, tmp_path: Path |
| 143 | +) -> None: |
| 144 | + found = _compared( |
| 145 | + repo, tmp_path, with_entry(_move(NEW_TEXT, NEW_HOST_TEXT)) |
| 146 | + ) |
| 147 | + assert found == [], found |
| 148 | + |
| 149 | + |
| 150 | +def test_an_entry_not_from_this_change_does_not_relax( |
| 151 | + repo: Path, tmp_path: Path |
| 152 | +) -> None: |
| 153 | + found = _compared( |
| 154 | + repo, |
| 155 | + tmp_path, |
| 156 | + None, |
| 157 | + at_checkpoint=with_entry(_move(NEW_TEXT, NEW_HOST_TEXT, id='SEED-9')), |
| 158 | + ) |
| 159 | + assert has(found, 'schema', WHERE), found |
| 160 | + |
| 161 | + |
| 162 | +def test_without_a_re_record_the_schema_is_still_held( |
| 163 | + repo: Path, tmp_path: Path |
| 164 | +) -> None: |
| 165 | + found = _compared( |
| 166 | + repo, |
| 167 | + tmp_path, |
| 168 | + with_entry(_move(REFERENCE_TEXT, 'refusal INTERNAL_ERROR')), |
| 169 | + re_recorded=False, |
| 170 | + ) |
| 171 | + assert has(found, 'schema', WHERE), found |
| 172 | + # Relaxed from materialize all the same: nothing past it fails. |
| 173 | + assert not has(found, 'payload', WHERE), found |
| 174 | + assert not has(found, 'result', WHERE), found |
0 commit comments