test_aff_unit.py
python
sha256:8461d44b77376fbf06fa7c3e085d309e3010fd8d5886d63c63e69ce118811ad4
docs: record AFF-b feature-tip SHAs after AFF-b-ISR commit.
Human
3 days ago
| 1 | """Unit tests for AFF ledger kind + Mode E resolution (§AFF.14).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | from pathlib import Path |
| 6 | from typing import get_args |
| 7 | |
| 8 | import pytest |
| 9 | import yaml |
| 10 | |
| 11 | from adapters.config import ADVERSARIAL_FREEZE_MODES, HONESTY_KEYS, HonestyConfig, load_config |
| 12 | from tests.fixtures.aff import AFF_DIGEST_PLACEHOLDER, AFF_FREEZE_REL, aff_body, load_aff_entry |
| 13 | from tests.support import seed_honesty_repo |
| 14 | from tools.adversarial_freeze import ( |
| 15 | aff_hold_bypassed, |
| 16 | aggregate_adversarial_authorization_states, |
| 17 | author_loop_complete, |
| 18 | frv_authorizing_freeze_paths, |
| 19 | ) |
| 20 | from tools.honesty.ledger import verify_chain |
| 21 | from tools.honesty.status import HonestyStatusOptions, _resolve_mode |
| 22 | from tools.honesty.types import AFF_POSTURES, AFF_VERDICTS, ENTRY_KINDS, HonestyErrorToken |
| 23 | from tools.honesty.validate import ( |
| 24 | EntryValidationError, |
| 25 | find_latest_adversarial_freeze_verdict, |
| 26 | find_matching_adversarial_freeze_pass, |
| 27 | find_matching_adversarial_freeze_skip, |
| 28 | validate_append_body, |
| 29 | ) |
| 30 | |
| 31 | |
| 32 | def _minimal(**overrides) -> dict: |
| 33 | body = load_aff_entry("aff-pass.json") |
| 34 | body.update(overrides) |
| 35 | return body |
| 36 | |
| 37 | |
| 38 | def test_aff_in_entry_kinds() -> None: |
| 39 | assert "adversarial_freeze" in ENTRY_KINDS |
| 40 | assert AFF_VERDICTS == frozenset({"pass", "findings", "blocked", "skip"}) |
| 41 | assert AFF_POSTURES == frozenset({"attack"}) |
| 42 | |
| 43 | |
| 44 | @pytest.mark.parametrize( |
| 45 | "fixture", |
| 46 | ["aff-pass.json", "aff-findings.json", "aff-blocked.json"], |
| 47 | ) |
| 48 | def test_validate_accepts_minimal_pass_findings_blocked(fixture: str) -> None: |
| 49 | validated = validate_append_body(kind="adversarial_freeze", body=load_aff_entry(fixture)) |
| 50 | assert validated["kind"] == "adversarial_freeze" |
| 51 | assert validated["aff_posture"] == "attack" |
| 52 | assert validated["reviewer_model"] == "thinking-high" |
| 53 | assert validated["producer_session_id"] == "aff-a-author-session" |
| 54 | assert validated["actor_session_id"] != validated["producer_session_id"] |
| 55 | |
| 56 | |
| 57 | def test_validate_accepts_minimal_skip() -> None: |
| 58 | validated = validate_append_body(kind="adversarial_freeze", body=load_aff_entry("aff-skip.json")) |
| 59 | assert validated["aff_verdict"] == "skip" |
| 60 | assert "aff_posture" not in validated |
| 61 | |
| 62 | |
| 63 | def test_client_v_true_exit_2() -> None: |
| 64 | with pytest.raises(EntryValidationError) as exc: |
| 65 | validate_append_body(kind="adversarial_freeze", body=_minimal(v=True)) |
| 66 | assert exc.value.exit_code == 2 |
| 67 | |
| 68 | |
| 69 | @pytest.mark.parametrize("bad_v", [0, 2, -1, 1.0, "1"]) |
| 70 | def test_client_v_not_exact_one_exit_2(bad_v) -> None: |
| 71 | with pytest.raises(EntryValidationError) as exc: |
| 72 | validate_append_body(kind="adversarial_freeze", body=_minimal(v=bad_v)) |
| 73 | assert exc.value.exit_code == 2 |
| 74 | |
| 75 | |
| 76 | def test_supplied_empty_ts_exit_2() -> None: |
| 77 | with pytest.raises(EntryValidationError) as exc: |
| 78 | validate_append_body(kind="adversarial_freeze", body=_minimal(ts="")) |
| 79 | assert exc.value.exit_code == 2 |
| 80 | |
| 81 | |
| 82 | def test_supplied_non_string_ts_exit_2() -> None: |
| 83 | with pytest.raises(EntryValidationError) as exc: |
| 84 | validate_append_body(kind="adversarial_freeze", body=_minimal(ts=123)) |
| 85 | assert exc.value.exit_code == 2 |
| 86 | |
| 87 | |
| 88 | def test_omitted_ts_accepted_for_server_fill() -> None: |
| 89 | body = _minimal() |
| 90 | body.pop("ts", None) |
| 91 | validated = validate_append_body(kind="adversarial_freeze", body=body) |
| 92 | assert "ts" not in validated or validated.get("ts") |
| 93 | |
| 94 | |
| 95 | def test_verify_chain_rejects_missing_ts() -> None: |
| 96 | entry = { |
| 97 | "v": 1, |
| 98 | "kind": "genesis", |
| 99 | "prev_hash": "0" * 64, |
| 100 | "entry_hash": "1" * 64, |
| 101 | } |
| 102 | assert verify_chain([entry]) == 22 |
| 103 | |
| 104 | |
| 105 | def test_verify_chain_rejects_v_true() -> None: |
| 106 | from tools.honesty.canonical import compute_entry_hash |
| 107 | from tools.honesty.genesis import GENESIS_PREV |
| 108 | |
| 109 | entry = {"v": True, "ts": "2026-01-01T00:00:00Z", "kind": "genesis", "prev_hash": GENESIS_PREV} |
| 110 | entry["entry_hash"] = compute_entry_hash(entry) |
| 111 | assert verify_chain([entry]) == 22 |
| 112 | |
| 113 | |
| 114 | @pytest.mark.parametrize( |
| 115 | "kind,extra", |
| 116 | [ |
| 117 | ( |
| 118 | "verification_evidence", |
| 119 | { |
| 120 | "bv_verdict": "pass", |
| 121 | "artifacts": [{"type": "test_output", "sha256": "b" * 64}], |
| 122 | }, |
| 123 | ), |
| 124 | ( |
| 125 | "independent_second_review", |
| 126 | {"isr_verdict": "pass", "producer_session_id": "p"}, |
| 127 | ), |
| 128 | ( |
| 129 | "freeze_review", |
| 130 | { |
| 131 | "gate": "substantive", |
| 132 | "freeze_verdict": "pass", |
| 133 | "artifact_digest": AFF_DIGEST_PLACEHOLDER, |
| 134 | "reviewer_model": "thinking-high", |
| 135 | }, |
| 136 | ), |
| 137 | ("adversarial_freeze", {"aff_verdict": "pass", "aff_posture": "attack", |
| 138 | "artifact_digest": AFF_DIGEST_PLACEHOLDER, |
| 139 | "producer_session_id": "p", "reviewer_model": "m"}), |
| 140 | ], |
| 141 | ) |
| 142 | def test_round_true_rejected_on_round_bearing_kinds(kind: str, extra: dict) -> None: |
| 143 | body = { |
| 144 | "actor_role": "verifier", |
| 145 | "actor_session_id": "a", |
| 146 | "phase_id": "X", |
| 147 | "frozen_spec": "docs/x.md", |
| 148 | "round": True, |
| 149 | **extra, |
| 150 | } |
| 151 | if kind == "adversarial_freeze": |
| 152 | body["actor_session_id"] = "a" |
| 153 | body["producer_session_id"] = "p" |
| 154 | with pytest.raises(EntryValidationError) as exc: |
| 155 | validate_append_body(kind=kind, body=body) |
| 156 | assert exc.value.exit_code == 2 |
| 157 | |
| 158 | |
| 159 | def test_missing_reviewer_model_exit_2() -> None: |
| 160 | body = _minimal() |
| 161 | del body["reviewer_model"] |
| 162 | with pytest.raises(EntryValidationError) as exc: |
| 163 | validate_append_body(kind="adversarial_freeze", body=body) |
| 164 | assert exc.value.exit_code == 2 |
| 165 | |
| 166 | |
| 167 | def test_same_session_ids_exit_2() -> None: |
| 168 | with pytest.raises(EntryValidationError) as exc: |
| 169 | validate_append_body( |
| 170 | kind="adversarial_freeze", |
| 171 | body=_minimal(actor_session_id="same", producer_session_id="same"), |
| 172 | ) |
| 173 | assert exc.value.exit_code == 2 |
| 174 | |
| 175 | |
| 176 | def test_missing_producer_session_on_pass_exit_2() -> None: |
| 177 | body = _minimal() |
| 178 | del body["producer_session_id"] |
| 179 | with pytest.raises(EntryValidationError) as exc: |
| 180 | validate_append_body(kind="adversarial_freeze", body=body) |
| 181 | assert exc.value.exit_code == 2 |
| 182 | |
| 183 | |
| 184 | def test_missing_aff_posture_on_pass_exit_2() -> None: |
| 185 | body = _minimal() |
| 186 | del body["aff_posture"] |
| 187 | with pytest.raises(EntryValidationError) as exc: |
| 188 | validate_append_body(kind="adversarial_freeze", body=body) |
| 189 | assert exc.value.exit_code == 2 |
| 190 | |
| 191 | |
| 192 | def test_aff_posture_not_attack_exit_2() -> None: |
| 193 | with pytest.raises(EntryValidationError) as exc: |
| 194 | validate_append_body(kind="adversarial_freeze", body=_minimal(aff_posture="defend")) |
| 195 | assert exc.value.exit_code == 2 |
| 196 | |
| 197 | |
| 198 | def test_skip_with_aff_posture_exit_2() -> None: |
| 199 | body = load_aff_entry("aff-skip.json") |
| 200 | body["aff_posture"] = "attack" |
| 201 | with pytest.raises(EntryValidationError) as exc: |
| 202 | validate_append_body(kind="adversarial_freeze", body=body) |
| 203 | assert exc.value.exit_code == 2 |
| 204 | |
| 205 | |
| 206 | def test_skip_non_owner_exit_23() -> None: |
| 207 | body = load_aff_entry("aff-skip.json") |
| 208 | body["actor_role"] = "verifier" |
| 209 | with pytest.raises(EntryValidationError) as exc: |
| 210 | validate_append_body(kind="adversarial_freeze", body=body) |
| 211 | assert exc.value.exit_code == 23 |
| 212 | |
| 213 | |
| 214 | def test_pass_non_verifier_exit_23() -> None: |
| 215 | with pytest.raises(EntryValidationError) as exc: |
| 216 | validate_append_body(kind="adversarial_freeze", body=_minimal(actor_role="producer")) |
| 217 | assert exc.value.exit_code == 23 |
| 218 | |
| 219 | |
| 220 | def test_bad_aff_verdict_exit_2() -> None: |
| 221 | with pytest.raises(EntryValidationError) as exc: |
| 222 | validate_append_body(kind="adversarial_freeze", body=_minimal(aff_verdict="ok")) |
| 223 | assert exc.value.exit_code == 2 |
| 224 | |
| 225 | |
| 226 | def test_round_lt_1_exit_2() -> None: |
| 227 | with pytest.raises(EntryValidationError) as exc: |
| 228 | validate_append_body(kind="adversarial_freeze", body=_minimal(round=0)) |
| 229 | assert exc.value.exit_code == 2 |
| 230 | |
| 231 | |
| 232 | def test_round_non_int_exit_2() -> None: |
| 233 | with pytest.raises(EntryValidationError) as exc: |
| 234 | validate_append_body(kind="adversarial_freeze", body=_minimal(round="1")) |
| 235 | assert exc.value.exit_code == 2 |
| 236 | |
| 237 | |
| 238 | def test_digest_not_sha256_hex_exit_2() -> None: |
| 239 | with pytest.raises(EntryValidationError) as exc: |
| 240 | validate_append_body( |
| 241 | kind="adversarial_freeze", |
| 242 | body=_minimal(artifact_digest="sha256:ZZZZ"), |
| 243 | ) |
| 244 | assert exc.value.exit_code == 2 |
| 245 | |
| 246 | |
| 247 | def test_genesis_forbid_aff_keys() -> None: |
| 248 | for key in ("aff_verdict", "aff_posture", "bound_freeze_review_hash", "side_check_path"): |
| 249 | with pytest.raises(EntryValidationError) as exc: |
| 250 | validate_append_body(kind="genesis", body={key: "x"}) |
| 251 | assert exc.value.exit_code == 2 |
| 252 | |
| 253 | |
| 254 | def test_adversarial_freeze_config_parse(repo_root: Path) -> None: |
| 255 | seed_honesty_repo(repo_root) |
| 256 | cfg_path = repo_root / ".overseer" / "config.yaml" |
| 257 | data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) |
| 258 | data["freeze_contract"] = { |
| 259 | "enabled": True, |
| 260 | "reviewer": "human", |
| 261 | "human_escalation": [], |
| 262 | } |
| 263 | for mode in ADVERSARIAL_FREEZE_MODES: |
| 264 | data["honesty"]["adversarial_freeze"] = mode |
| 265 | cfg_path.write_text(yaml.safe_dump(data), encoding="utf-8") |
| 266 | assert load_config(cfg_path).honesty.adversarial_freeze == mode |
| 267 | |
| 268 | data["honesty"]["adversarial_freeze"] = "maybe" |
| 269 | cfg_path.write_text(yaml.safe_dump(data), encoding="utf-8") |
| 270 | with pytest.raises(Exception, match="adversarial_freeze"): |
| 271 | load_config(cfg_path) |
| 272 | |
| 273 | |
| 274 | def test_derived_suggest_from_security(repo_root: Path) -> None: |
| 275 | seed_honesty_repo(repo_root) |
| 276 | cfg_path = repo_root / ".overseer" / "config.yaml" |
| 277 | data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) |
| 278 | data["honesty"].pop("adversarial_freeze", None) |
| 279 | data["freeze_contract"] = { |
| 280 | "enabled": True, |
| 281 | "reviewer": "human", |
| 282 | "human_escalation": ["security"], |
| 283 | } |
| 284 | cfg_path.write_text(yaml.safe_dump(data), encoding="utf-8") |
| 285 | assert load_config(cfg_path).honesty.adversarial_freeze == "suggest" |
| 286 | |
| 287 | |
| 288 | def test_derived_off_without_security(repo_root: Path) -> None: |
| 289 | seed_honesty_repo(repo_root) |
| 290 | cfg_path = repo_root / ".overseer" / "config.yaml" |
| 291 | data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) |
| 292 | data["honesty"].pop("adversarial_freeze", None) |
| 293 | data["freeze_contract"] = { |
| 294 | "enabled": True, |
| 295 | "reviewer": "human", |
| 296 | "human_escalation": [], |
| 297 | } |
| 298 | cfg_path.write_text(yaml.safe_dump(data), encoding="utf-8") |
| 299 | assert load_config(cfg_path).honesty.adversarial_freeze == "off" |
| 300 | |
| 301 | |
| 302 | def test_explicit_off_wins_over_security(repo_root: Path) -> None: |
| 303 | seed_honesty_repo(repo_root) |
| 304 | cfg_path = repo_root / ".overseer" / "config.yaml" |
| 305 | data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) |
| 306 | data["honesty"]["adversarial_freeze"] = "off" |
| 307 | data["freeze_contract"] = { |
| 308 | "enabled": True, |
| 309 | "reviewer": "human", |
| 310 | "human_escalation": ["security"], |
| 311 | } |
| 312 | cfg_path.write_text(yaml.safe_dump(data), encoding="utf-8") |
| 313 | assert load_config(cfg_path).honesty.adversarial_freeze == "off" |
| 314 | |
| 315 | |
| 316 | def test_require_never_derived(repo_root: Path) -> None: |
| 317 | seed_honesty_repo(repo_root) |
| 318 | cfg_path = repo_root / ".overseer" / "config.yaml" |
| 319 | data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) |
| 320 | data["honesty"].pop("adversarial_freeze", None) |
| 321 | data["freeze_contract"] = { |
| 322 | "enabled": True, |
| 323 | "reviewer": "human", |
| 324 | "human_escalation": ["security"], |
| 325 | } |
| 326 | cfg_path.write_text(yaml.safe_dump(data), encoding="utf-8") |
| 327 | assert load_config(cfg_path).honesty.adversarial_freeze != "require" |
| 328 | |
| 329 | |
| 330 | def test_adversarial_freeze_in_honesty_keys() -> None: |
| 331 | assert "adversarial_freeze" in HONESTY_KEYS |
| 332 | |
| 333 | |
| 334 | def test_honesty_config_field_default_suggest() -> None: |
| 335 | assert HonestyConfig().adversarial_freeze == "suggest" |
| 336 | |
| 337 | |
| 338 | def test_error_token_includes_missing_adversarial_freeze() -> None: |
| 339 | assert "missing_adversarial_freeze" in get_args(HonestyErrorToken) |
| 340 | |
| 341 | |
| 342 | def test_resolve_mode_e_invariants() -> None: |
| 343 | assert ( |
| 344 | _resolve_mode( |
| 345 | HonestyStatusOptions( |
| 346 | hook=None, |
| 347 | artifact=None, |
| 348 | adversarial_freeze="AFF", |
| 349 | frozen_spec="docs/x.md", |
| 350 | ) |
| 351 | ) |
| 352 | == "mode_e" |
| 353 | ) |
| 354 | assert ( |
| 355 | _resolve_mode( |
| 356 | HonestyStatusOptions( |
| 357 | hook=None, |
| 358 | artifact=None, |
| 359 | adversarial_freeze="AFF", |
| 360 | producer_session="author", |
| 361 | ) |
| 362 | ) |
| 363 | == "mode_e" |
| 364 | ) |
| 365 | assert ( |
| 366 | _resolve_mode( |
| 367 | HonestyStatusOptions( |
| 368 | hook=None, |
| 369 | artifact=None, |
| 370 | adversarial_freeze="AFF", |
| 371 | producer_session="author", |
| 372 | frozen_spec="docs/x.md", |
| 373 | ) |
| 374 | ) |
| 375 | == "mode_e" |
| 376 | ) |
| 377 | assert ( |
| 378 | _resolve_mode(HonestyStatusOptions(hook=None, artifact=None, adversarial_freeze="AFF")) |
| 379 | == "mode_e" |
| 380 | ) |
| 381 | assert ( |
| 382 | _resolve_mode( |
| 383 | HonestyStatusOptions( |
| 384 | hook=None, |
| 385 | artifact=None, |
| 386 | adversarial_freeze="AFF", |
| 387 | frozen_spec="docs/x.md", |
| 388 | artifact_digest=AFF_DIGEST_PLACEHOLDER, |
| 389 | ) |
| 390 | ) |
| 391 | == "mode_e" |
| 392 | ) |
| 393 | # digest without Mode E → usage |
| 394 | assert ( |
| 395 | _resolve_mode( |
| 396 | HonestyStatusOptions( |
| 397 | hook=None, |
| 398 | artifact=None, |
| 399 | artifact_digest=AFF_DIGEST_PLACEHOLDER, |
| 400 | ) |
| 401 | ) |
| 402 | is None |
| 403 | ) |
| 404 | # Mode E + digest without frozen-spec → usage |
| 405 | assert ( |
| 406 | _resolve_mode( |
| 407 | HonestyStatusOptions( |
| 408 | hook=None, |
| 409 | artifact=None, |
| 410 | adversarial_freeze="AFF", |
| 411 | artifact_digest=AFF_DIGEST_PLACEHOLDER, |
| 412 | ) |
| 413 | ) |
| 414 | is None |
| 415 | ) |
| 416 | # Mode E + Mode D → usage |
| 417 | assert ( |
| 418 | _resolve_mode( |
| 419 | HonestyStatusOptions( |
| 420 | hook=None, |
| 421 | artifact=None, |
| 422 | adversarial_freeze="AFF", |
| 423 | independent_second_review="ISR-b", |
| 424 | ) |
| 425 | ) |
| 426 | is None |
| 427 | ) |
| 428 | # existing non-regular frozen-spec + valid digest still Mode E at resolve layer |
| 429 | assert ( |
| 430 | _resolve_mode( |
| 431 | HonestyStatusOptions( |
| 432 | hook=None, |
| 433 | artifact=None, |
| 434 | adversarial_freeze="AFF", |
| 435 | frozen_spec="/tmp", # path shape only; resolve_mode does not stat |
| 436 | artifact_digest=AFF_DIGEST_PLACEHOLDER, |
| 437 | ) |
| 438 | ) |
| 439 | == "mode_e" |
| 440 | ) |
| 441 | |
| 442 | |
| 443 | def _eligible_entries() -> list[dict]: |
| 444 | digest = AFF_DIGEST_PLACEHOLDER |
| 445 | path = AFF_FREEZE_REL |
| 446 | pass1 = aff_body(artifact_digest=digest, round=1, entry_hash="p1" * 32) |
| 447 | findings = aff_body( |
| 448 | "aff-findings.json", |
| 449 | artifact_digest=digest, |
| 450 | round=2, |
| 451 | actor_session_id="adv-3", |
| 452 | entry_hash="f1" * 32, |
| 453 | ) |
| 454 | blocked = aff_body( |
| 455 | "aff-blocked.json", |
| 456 | artifact_digest=digest, |
| 457 | round=2, |
| 458 | actor_session_id="adv-4", |
| 459 | entry_hash="b1" * 32, |
| 460 | ) |
| 461 | skip = aff_body( |
| 462 | "aff-skip.json", |
| 463 | artifact_digest=digest, |
| 464 | round=2, |
| 465 | entry_hash="s1" * 32, |
| 466 | ) |
| 467 | return pass1, findings, blocked, skip, path, digest |
| 468 | |
| 469 | |
| 470 | def test_auto_hold_match_ignores_phase_id() -> None: |
| 471 | pass1, _, _, _, path, digest = _eligible_entries() |
| 472 | pass1["phase_id"] = "AFF" # not AFF-b |
| 473 | winner = find_matching_adversarial_freeze_pass( |
| 474 | [pass1], frozen_spec=path, artifact_digest=digest, phase_id=None |
| 475 | ) |
| 476 | assert winner is not None |
| 477 | assert winner["phase_id"] == "AFF" |
| 478 | |
| 479 | |
| 480 | def test_mode_e_optional_phase_pin() -> None: |
| 481 | pass1, _, _, _, path, digest = _eligible_entries() |
| 482 | assert ( |
| 483 | find_latest_adversarial_freeze_verdict( |
| 484 | [pass1], frozen_spec=path, artifact_digest=digest, phase_id="OTHER" |
| 485 | ) |
| 486 | is None |
| 487 | ) |
| 488 | assert ( |
| 489 | find_latest_adversarial_freeze_verdict( |
| 490 | [pass1], frozen_spec=path, artifact_digest=digest, phase_id="AFF" |
| 491 | ) |
| 492 | is not None |
| 493 | ) |
| 494 | |
| 495 | |
| 496 | def test_skip_match_ignores_producer_session() -> None: |
| 497 | _, _, _, skip, path, digest = _eligible_entries() |
| 498 | winner = find_matching_adversarial_freeze_skip( |
| 499 | [skip], frozen_spec=path, artifact_digest=digest, phase_id=None |
| 500 | ) |
| 501 | assert winner is not None |
| 502 | # producer pin is ignored by skip wrapper (not passed through as filter on skip body) |
| 503 | latest = find_latest_adversarial_freeze_verdict( |
| 504 | [skip], |
| 505 | frozen_spec=path, |
| 506 | artifact_digest=digest, |
| 507 | producer_session="ignored-author", |
| 508 | ) |
| 509 | assert latest is not None |
| 510 | assert latest["aff_verdict"] == "skip" |
| 511 | |
| 512 | |
| 513 | def test_pass_then_findings_never_returns_older_pass() -> None: |
| 514 | pass1, findings, _, _, path, digest = _eligible_entries() |
| 515 | assert ( |
| 516 | find_matching_adversarial_freeze_pass( |
| 517 | [pass1, findings], frozen_spec=path, artifact_digest=digest |
| 518 | ) |
| 519 | is None |
| 520 | ) |
| 521 | latest = find_latest_adversarial_freeze_verdict( |
| 522 | [pass1, findings], frozen_spec=path, artifact_digest=digest |
| 523 | ) |
| 524 | assert latest is not None |
| 525 | assert latest["aff_verdict"] == "findings" |
| 526 | |
| 527 | |
| 528 | def test_pass_then_blocked_never_returns_older_pass() -> None: |
| 529 | pass1, _, blocked, _, path, digest = _eligible_entries() |
| 530 | assert ( |
| 531 | find_matching_adversarial_freeze_pass( |
| 532 | [pass1, blocked], frozen_spec=path, artifact_digest=digest |
| 533 | ) |
| 534 | is None |
| 535 | ) |
| 536 | |
| 537 | |
| 538 | def test_pass_then_skip_never_returns_older_pass() -> None: |
| 539 | pass1, _, _, skip, path, digest = _eligible_entries() |
| 540 | assert ( |
| 541 | find_matching_adversarial_freeze_pass( |
| 542 | [pass1, skip], frozen_spec=path, artifact_digest=digest |
| 543 | ) |
| 544 | is None |
| 545 | ) |
| 546 | assert ( |
| 547 | find_matching_adversarial_freeze_skip( |
| 548 | [pass1, skip], frozen_spec=path, artifact_digest=digest |
| 549 | ) |
| 550 | is not None |
| 551 | ) |
| 552 | |
| 553 | |
| 554 | def test_author_loop_complete_predicates() -> None: |
| 555 | digest = AFF_DIGEST_PLACEHOLDER |
| 556 | assert author_loop_complete("substantive", stamp_digest=None, current_digest=digest) is True |
| 557 | assert ( |
| 558 | author_loop_complete("mechanical_only", stamp_digest=digest, current_digest=digest) |
| 559 | is True |
| 560 | ) |
| 561 | assert ( |
| 562 | author_loop_complete("mechanical_only", stamp_digest=None, current_digest=digest) is False |
| 563 | ) |
| 564 | other = "sha256:" + ("b" * 64) |
| 565 | assert ( |
| 566 | author_loop_complete("mechanical_only", stamp_digest=other, current_digest=digest) is False |
| 567 | ) |
| 568 | assert author_loop_complete("absent", stamp_digest=digest, current_digest=digest) is False |
| 569 | |
| 570 | |
| 571 | def test_aff_hold_bypassed(repo_root: Path) -> None: |
| 572 | from tests.fixtures.aff import seed_aff_repo |
| 573 | |
| 574 | cfg = seed_aff_repo(repo_root, adversarial_freeze="suggest", honesty_enabled=True) |
| 575 | assert aff_hold_bypassed(cfg) is False |
| 576 | cfg_off = seed_aff_repo(repo_root, adversarial_freeze="off", honesty_enabled=True) |
| 577 | assert aff_hold_bypassed(cfg_off) is True |
| 578 | cfg_dis = seed_aff_repo(repo_root, adversarial_freeze="suggest", honesty_enabled=False) |
| 579 | assert aff_hold_bypassed(cfg_dis) is True |
| 580 | cfg_req = seed_aff_repo(repo_root, adversarial_freeze="require", honesty_enabled=True) |
| 581 | assert aff_hold_bypassed(cfg_req) is False |
| 582 | |
| 583 | |
| 584 | def test_helper_off_never_pending(repo_root: Path) -> None: |
| 585 | from tests.fixtures.aff import seed_aff_repo |
| 586 | from tools.adversarial_freeze import adversarial_authorization_state |
| 587 | |
| 588 | cfg = seed_aff_repo(repo_root, adversarial_freeze="off") |
| 589 | auth = adversarial_authorization_state(repo_root, repo_root / AFF_FREEZE_REL, config=cfg) |
| 590 | assert auth.state == "off" |
| 591 | assert auth.state != "pending" |
| 592 | |
| 593 | |
| 594 | def test_resolver_eligibility_rejects_malformed() -> None: |
| 595 | path = AFF_FREEZE_REL |
| 596 | digest = AFF_DIGEST_PLACEHOLDER |
| 597 | base = aff_body(artifact_digest=digest) |
| 598 | |
| 599 | empty_phase = {**base, "phase_id": ""} |
| 600 | assert ( |
| 601 | find_latest_adversarial_freeze_verdict( |
| 602 | [empty_phase], frozen_spec=path, artifact_digest=digest |
| 603 | ) |
| 604 | is None |
| 605 | ) |
| 606 | |
| 607 | bool_round = {**base, "round": True} |
| 608 | assert ( |
| 609 | find_latest_adversarial_freeze_verdict( |
| 610 | [bool_round], frozen_spec=path, artifact_digest=digest |
| 611 | ) |
| 612 | is None |
| 613 | ) |
| 614 | |
| 615 | no_model = {**base} |
| 616 | del no_model["reviewer_model"] |
| 617 | assert ( |
| 618 | find_latest_adversarial_freeze_verdict( |
| 619 | [no_model], frozen_spec=path, artifact_digest=digest |
| 620 | ) |
| 621 | is None |
| 622 | ) |
| 623 | |
| 624 | skip_bad_phase = aff_body("aff-skip.json", artifact_digest=digest, phase_id="") |
| 625 | assert ( |
| 626 | find_latest_adversarial_freeze_verdict( |
| 627 | [skip_bad_phase], frozen_spec=path, artifact_digest=digest |
| 628 | ) |
| 629 | is None |
| 630 | ) |
| 631 | |
| 632 | |
| 633 | def test_frv_authorizing_freeze_paths_only_substantive(repo_root: Path) -> None: |
| 634 | from tests.fixtures.aff import seed_aff_repo, write_mechanical_stamp |
| 635 | from tools.honesty.ledger import append_entry |
| 636 | from tools.honesty.types import LedgerAppendOptions |
| 637 | |
| 638 | cfg = seed_aff_repo(repo_root, adversarial_freeze="suggest") |
| 639 | digest = write_mechanical_stamp(repo_root) |
| 640 | path = repo_root / AFF_FREEZE_REL |
| 641 | # mechanical only — not substantive |
| 642 | only_mech = frv_authorizing_freeze_paths( |
| 643 | repo_root, [path], phase_id="AFF-b", config=cfg |
| 644 | ) |
| 645 | assert only_mech == [] |
| 646 | |
| 647 | append_entry( |
| 648 | config=cfg, |
| 649 | repo_root=repo_root, |
| 650 | options=LedgerAppendOptions( |
| 651 | kind="freeze_review", |
| 652 | body={ |
| 653 | "actor_role": "verifier", |
| 654 | "actor_session_id": "frv-1", |
| 655 | "phase_id": "AFF-b", |
| 656 | "frozen_spec": AFF_FREEZE_REL, |
| 657 | "round": 1, |
| 658 | "gate": "substantive", |
| 659 | "freeze_verdict": "pass", |
| 660 | "artifact_digest": digest, |
| 661 | "reviewer_model": "thinking-high", |
| 662 | }, |
| 663 | ), |
| 664 | ) |
| 665 | authorizing = frv_authorizing_freeze_paths( |
| 666 | repo_root, [path], phase_id="AFF-b", config=cfg |
| 667 | ) |
| 668 | assert authorizing == [path] |
| 669 | |
| 670 | |
| 671 | def test_aggregate_rank_absent_pending_skipped_pass() -> None: |
| 672 | assert aggregate_adversarial_authorization_states(["pass", "pending"]) == "pending" |
| 673 | assert aggregate_adversarial_authorization_states(["pass", "absent"]) == "absent" |
| 674 | assert aggregate_adversarial_authorization_states(["skipped", "pass"]) == "skipped" |
| 675 | assert aggregate_adversarial_authorization_states(["pass", "pass"]) == "pass" |
| 676 | assert ( |
| 677 | aggregate_adversarial_authorization_states(["absent", "pending", "skipped", "pass"]) |
| 678 | == "absent" |
| 679 | ) |
File History
1 commit
sha256:8461d44b77376fbf06fa7c3e085d309e3010fd8d5886d63c63e69ce118811ad4
docs: record AFF-b feature-tip SHAs after AFF-b-ISR commit.
Human
3 days ago