Audit Specs

AuditSpec is a serializable configuration object for standard updatesupport audits. Use it when an audit should be reproducible, checked into a model-review folder, generated by another system, or rerun in CI.

import updatesupport as us

spec = us.AuditSpec(
    kind="public_descent",
    public=["AGE_BAND", "SEX"],
    hidden=["AGE_BAND", "SEX", "OCC_MAJOR", "WKHP_BAND"],
    target="income_over_threshold",
    weight="sample_weight",
    candidate_refinements=["OCC_MAJOR", "WKHP_BAND"],
    q={"name": "bounded_shift", "radius": 0.5},
    min_cell_weight=25,
    title="Income-Threshold Representation Audit",
)

run = spec.run(rows_or_frame)

print(run.to_markdown())
print(run.to_json())
print(run.to_tables().keys())

The executed AuditRun keeps both the spec and report:

payload = run.as_dict()
payload["spec"]
payload["report"]

Supported Kinds

Use kind="public_descent" for the standard report:

spec = us.AuditSpec(
    kind="public_descent",
    public=["segment"],
    hidden=["segment", "region", "tenure_band"],
    target="outcome_rate",
    q="saturated",
)

Use kind="sensitivity" for robustness grids:

spec = us.AuditSpec(
    kind="sensitivity",
    public=["segment"],
    hidden=["segment", "region", "tenure_band"],
    target="outcome_rate",
    q_presets=[
        "saturated",
        {"name": "bounded_shift", "radius": 0.5},
        "observed",
    ],
    min_cell_weights=[1, 10, 25],
)

Use kind="frontier" for public-representation search:

spec = us.AuditSpec(
    kind="frontier",
    public=["segment"],
    hidden=["segment", "region", "tenure_band", "channel"],
    target="outcome_rate",
    candidate_refinements=["region", "tenure_band", "channel"],
    q_presets=["saturated", {"name": "bounded_shift", "radius": 0.5}],
    ambiguity_limit=0.01,
    bucket_budget=40,
    search="beam",
)

Use kind="certificate" when the same search should produce a pass/fail representation-stability certificate:

spec = us.AuditSpec(
    kind="certificate",
    public=["segment"],
    hidden=["segment", "region", "tenure_band", "channel"],
    target="outcome_rate",
    candidate_refinements=["region", "tenure_band", "channel"],
    q_presets=["saturated", {"name": "bounded_shift", "radius": 0.5}],
    ambiguity_limit=0.01,
    bucket_budget=40,
    search="exhaustive",
)

Certificate specs require ambiguity_limit. By default, heuristic searches such as greedy or beam are marked inconclusive rather than passed; set exact_required=False when the certificate should cover only evaluated candidates.

Frontier and certificate specs can also request experimental residopt screening for L2-budget stress tests:

spec = us.AuditSpec(
    kind="certificate",
    public=["segment"],
    hidden=["segment", "region", "tenure_band", "channel"],
    target="outcome_rate",
    candidate_refinements=["region", "tenure_band", "channel"],
    q_presets=[{"name": "l2_budget", "radius": 0.05}],
    ambiguity_limit=0.01,
    screening_backend="residopt",
)

The resulting frontier or certificate report records conservative endpoints, exact fallbacks, and avoided exact solves in Markdown and structured exports.

run_audit(...) also accepts a plain mapping, which is useful when loading a spec from JSON or YAML:

run = us.run_audit(spec_mapping, rows_or_frame)

Q Presets

Specs use serializable Q descriptions:

"saturated"
{"name": "bounded_shift", "radius": 0.5}
{"name": "tv_budget", "radius": 0.1, "backend": "cvxpy"}
{"name": "tv_budget", "radius": 0.1, "backend": "cvxpy", "solver": "SCIP"}
{"name": "fiber_support_floor", "solver": "SCIP", "settings": {"min_active": 2, "min_share": 0.1}}
{"name": "observed"}

solver_options may also be supplied as a JSON object and are forwarded to cvxpy.Problem.solve(...) for CVXPY-backed presets. Preset-specific values that do not fit the standard radius or cost fields live under settings.

For non-serializable custom environments, custom constraint builders, or plugin-specific runtime objects, call the lower-level Python APIs directly.

Current Scope

The first AuditSpec slice covers public-descent reports, sensitivity reports, and public-representation frontier search. Causal reporting suites, artifact directory writers, and plugin-specific spec extensions can build on the same shape without changing the report APIs.