File size: 2,918 Bytes
97b64b9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | """The verification test-case taxonomy: ``case_type`` -> ground-truth verdict.
Each :class:`CaseSpec` encodes one row of the signature-verification test
plan: what should actually be rendered into the target signature box
(``signature_mode``), whether a companion box on the same page should also
be filled with its own correctly-authorized signature (``fill_companion`` --
only meaningful for the multi-signer-context cases), and the ground-truth
``verdict``/``reject_code`` a downstream verifier is expected to produce.
Driven by the existing ``quality.case_type`` config field (see
``configs/examples/hard_degraded.yaml`` for its prior, simpler use as a
plain metadata label) -- setting it to one of the codes below switches
:meth:`~src.generator.GeneratorContext.run_sample` into scenario-driven
generation. Any other value (or ``None``) leaves generation entirely
unaffected.
"""
from __future__ import annotations
from dataclasses import dataclass
SignatureMode = str # one of the _SIGNATURE_MODES below, kept as a plain str for simplicity
NO_SIGNATURE = "NO_SIGNATURE"
IDENTITY_MISMATCH = "IDENTITY_MISMATCH"
ROLE_MISMATCH = "ROLE_MISMATCH"
REQUIRED_SIGNER_ABSENT = "REQUIRED_SIGNER_ABSENT"
@dataclass(frozen=True)
class CaseSpec:
"""One row of the verification test-case taxonomy."""
code: str
description: str
verdict: str # "PASS" | "REJECT"
reject_code: "str | None"
signature_mode: SignatureMode
fill_companion: bool = False
CASE_TABLE: dict[str, CaseSpec] = {
"1a": CaseSpec("1a", "Correct signer signs normally", "PASS", None, "genuine_correct"),
"1b": CaseSpec("1b", "Correct signer, natural pen variation applied", "PASS", None, "genuine_variation"),
"1c": CaseSpec("1c", "Multi-signer form, both sign correctly", "PASS", None, "genuine_correct", fill_companion=True),
"1d": CaseSpec("1d", "Correct signer, scan degraded to test robustness", "PASS", None, "genuine_correct"),
"2a": CaseSpec("2a", "Box left completely blank", "REJECT", NO_SIGNATURE, "blank"),
"2b": CaseSpec("2b", "Printed/typed name only, no handwriting", "REJECT", NO_SIGNATURE, "printed_text"),
"3a": CaseSpec("3a", "Wrong real person signs the box", "REJECT", IDENTITY_MISMATCH, "wrong_signer_genuine"),
"3b": CaseSpec("3b", "Skilled-forgery sample used", "REJECT", IDENTITY_MISMATCH, "forged_skilled"),
"4a": CaseSpec("4a", "Authorized signer, but wrong role's box", "REJECT", ROLE_MISMATCH, "role_swap", fill_companion=True),
"4b": CaseSpec("4b", "Signer from a different form entirely", "REJECT", ROLE_MISMATCH, "foreign_template_signer", fill_companion=True),
"5a": CaseSpec("5a", "Required signer's box left empty", "REJECT", REQUIRED_SIGNER_ABSENT, "blank", fill_companion=True),
"5b": CaseSpec("5b", "Someone else signs in the required signer's place", "REJECT", REQUIRED_SIGNER_ABSENT, "wrong_signer_genuine", fill_companion=True),
}
|