Files
imbad0202__academic-researc…/scripts/test_check_setup_cross_model_parity.py
Edward Cheng-I Wu a25ada2812 feat(lint): #491 defrift lock (canonical enforcement sentence) + SETUP parity + manifest gap (#492)
* feat(lint): #491 defrift lock for Phase Boundary enforcement sentence + SETUP parity + manifest gap

Three pieces, all follow-ups from the 2026-07-04 harness-retirement pass:

1. check_v3_9_2_phase_boundary.py gains invariant 4: every Bucket A block's
   enforcement paragraph must carry the canonical sentence verbatim
   (CANONICAL_ENFORCEMENT, version-matched v3.9.2/v3.9.4; per-file tails
   free). The previous copy went factually stale repo-wide for a month with
   no lint noticing (B4-F01) — this converts 25 hand-synced copies into one
   lock. +7 mutation tests incl. the exact stale-sentence regression case.

2. New check_setup_cross_model_parity.py (+6 tests): SETUP en/zh-TW must
   carry the same ARS_CROSS_MODEL example values and every value must exist
   in the canonical lineup doc (the B4-F02 drift class). Fail-closed on
   zero extracted examples. Wired into spec-consistency.yml.

3. _ci_pytest_manifest.toml gains v3.9.4-temporal-verification — the test
   whose absence made PR #490 local-green/CI-red (bibliography_agent sha256
   pin only checked in CI). Local manifest now catches it: 58 -> 60 entries.

Verification: manifest drift guard green; full manifest 60/60 green;
phase-boundary lint green on repo baseline; personal-boundary 993 files
0 violations.

Closes #491

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

* fix(lint): scope canonical membership to model tables only (codex review P1)

The membership check accepted any backticked token in the canonical doc,
so a SETUP example reverting to gpt-5.4-pro would false-pass on the
legacy-accepted NOTE — the exact B4-F02 drift class the lint exists to
catch. Membership now parses only the "API ID" table columns; ids in
surrounding prose do not count. +3 tests incl. the literal legacy-revert
regression case + table-parser fail-closed.

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

* fix(lint): exclude wildcard prefix tokens from canonical model ids (codex re-review P2)

The compat table's "any non-`gpt-*`/`gemini-*` id" prose sits in an API ID
column, leaking glob patterns into the allowed set. Globs are prefix
patterns, not model ids — filtered, with a regression test.

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

* refactor(lint): /simplify pass — dedupe update guidance, shared module loader, cross-refs

- Simplification: the "update + sweep" maintenance guidance was triplicated
  inside the defrift lint itself with a hand-typed file count; now stated
  once in the error message with len(BUCKET_A_AGENTS) interpolated, and the
  mirror wording corrected (mirrors follow mechanically via
  check_agents_mirror_sync.py, not by hand-sweeping).
- Reuse (R1, option b): CANONICAL_ENFORCEMENT stays lint-local by design
  (factual status prose, not a behavioral firm rule) — rationale in the
  constant comment + "Related mechanisms" cross-ref in firm_rules.md so the
  two canonical-sync mechanisms know about each other.
- Reuse (R2): tests/test_helpers.py gains load_module_from_path(); both new
  test files use it (6 pre-existing local copies migrate at next edit).
- Efficiency note: workflow comment marks the 2x pytest.yml overlap as the
  accepted manifest pattern.

All lints + 21 tests + full 60-entry manifest green; firm-rules sync green.

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 13:35:58 +08:00

122 lines
5.0 KiB
Python

"""Unit tests for check_setup_cross_model_parity.py (#491 fold-in)."""
import unittest
from pathlib import Path
from tests.test_helpers import load_module_from_path, run_script
SCRIPT = Path(__file__).resolve().parent / "check_setup_cross_model_parity.py"
EN_OK = 'export ARS_CROSS_MODEL="gpt-5.5"\n# or: export ARS_CROSS_MODEL="gemini-3.1-pro-preview"\n'
ZH_OK = EN_OK
CANONICAL_OK = (
"| Model | API ID | Provider |\n"
"|-------|--------|----------|\n"
"| GPT-5.5 | `gpt-5.5` | OpenAI |\n"
"| Gemini 3.1 Pro | `gemini-3.1-pro-preview` | Google |\n"
"\n"
"(`gpt-5.4` / `gpt-5.4-pro` remain accepted for existing setups.)\n"
)
def _load_module():
return load_module_from_path("check_setup_cross_model_parity", SCRIPT)
class SetupCrossModelParityTests(unittest.TestCase):
def test_repo_baseline_passes(self) -> None:
"""The committed SETUP + canonical doc state must pass."""
result = run_script(SCRIPT)
self.assertEqual(result.returncode, 0, msg=f"stderr: {result.stderr}")
self.assertIn("PASSED", result.stdout)
def test_clean_fixture_passes(self) -> None:
module = _load_module()
self.assertEqual(module.check(EN_OK, ZH_OK, CANONICAL_OK), [])
def test_en_zh_drift_fails(self) -> None:
"""One-sided edit (the B4-F02 shape: en updated, zh-TW forgotten)."""
module = _load_module()
zh_stale = 'export ARS_CROSS_MODEL="gpt-5.4-pro"\n'
errors = module.check(EN_OK, zh_stale, CANONICAL_OK)
self.assertTrue(any("drift" in e for e in errors), msg=f"errors: {errors}")
def test_legacy_id_in_prose_note_does_not_count(self) -> None:
"""codex P1 regression (PR #492): `gpt-5.4-pro` is backticked in the
canonical doc's legacy-accepted NOTE but absent from the model tables —
a SETUP example reverting to it must FAIL, not pass on the note."""
module = _load_module()
stale = 'export ARS_CROSS_MODEL="gpt-5.4-pro"\n'
errors = module.check(stale, stale, CANONICAL_OK)
self.assertTrue(
any("gpt-5.4-pro" in e and "not in" in e for e in errors),
msg=f"errors: {errors}",
)
def test_canonical_table_parse_fails_closed(self) -> None:
"""No 'API ID' table in the canonical doc = parser stale = error."""
module = _load_module()
errors = module.check(EN_OK, ZH_OK, "prose only, `gpt-5.5` backticked")
self.assertTrue(
any("parser went stale" in e for e in errors), msg=f"errors: {errors}"
)
def test_compat_table_column_counts(self) -> None:
"""Ids in the compat table's 'Example API ID(s)' column are members."""
module = _load_module()
canonical = CANONICAL_OK + (
"\n| Provider | Example API ID(s) | Endpoint |\n"
"|----------|-------------------|----------|\n"
"| DeepSeek | `deepseek-v4-pro` | https://api.deepseek.com/v1 |\n"
)
ids = module.canonical_model_ids(canonical)
self.assertIn("deepseek-v4-pro", ids)
self.assertNotIn("gpt-5.4-pro", ids)
def test_wildcard_prefix_tokens_are_not_ids(self) -> None:
"""codex P2 regression (PR #492): the compat table's "any
non-`gpt-*`/`gemini-*` id" prose sits in an API ID column — globs are
prefix patterns, not model ids, and a SETUP example of `gpt-*` must
fail, not pass on the leaked token."""
module = _load_module()
canonical = CANONICAL_OK + (
"\n| Provider | Example API ID(s) | Endpoint |\n"
"|----------|-------------------|----------|\n"
"| Any OpenAI-compatible | any non-`gpt-*`/`gemini-*` id | any |\n"
)
self.assertNotIn("gpt-*", module.canonical_model_ids(canonical))
glob_setup = 'export ARS_CROSS_MODEL="gpt-*"\n'
errors = module.check(glob_setup, glob_setup, canonical)
self.assertTrue(
any("gpt-*" in e and "not in" in e for e in errors),
msg=f"errors: {errors}",
)
def test_unknown_model_fails(self) -> None:
"""Example naming a model outside the canonical lineup."""
module = _load_module()
bad = 'export ARS_CROSS_MODEL="gpt-9.9-imaginary"\n'
errors = module.check(bad, bad, CANONICAL_OK)
self.assertTrue(
any("gpt-9.9-imaginary" in e and "canonical" in e for e in errors),
msg=f"errors: {errors}",
)
def test_zero_examples_fails_closed(self) -> None:
"""Regex-went-stale / block-removed must be an error, not a pass."""
module = _load_module()
errors = module.check("no examples here", ZH_OK, CANONICAL_OK)
self.assertTrue(
any("Fail-closed" in e for e in errors), msg=f"errors: {errors}"
)
def test_commented_example_lines_are_extracted(self) -> None:
"""`# or:` alternates count — they are user-pasteable examples too."""
module = _load_module()
ids = module.extract_ids(EN_OK)
self.assertEqual(ids, ["gpt-5.5", "gemini-3.1-pro-preview"])
if __name__ == "__main__":
unittest.main()