audit: unify audit-of-audit sampling rule (gap 2)

Single sampling rule; track 3 (#244) is authoritative for WHO is
mandatory, track 5 (#238) for HOW the rest are drawn:

- Mandatory (1.0): golden-task records + rebuild / refreeze /
  escalation records + third-failure near-complete still-failed
  cases (mandatory_triggers, full list per case). Track 3's old
  deterministic every-10th ordinary rule is removed (it drew zero
  from batches under 10 ordinary records and was predictable);
  track 5's old narrow mandatory list is expanded with golden /
  refreeze / escalate. blocked_quota stays non-mandatory.
- Random tiers: normal 0.10, critical-path 0.50, seed required
  and recorded, ceil so a non-empty group is never rounded to
  zero. 0.10/0.50 are TEST DEFAULTS, not approved production
  values; production rates remain a user decision.
- One pass, no double counting: mandatory records leave the
  random pools before drawing; a multi-trigger record (e.g.
  golden + rebuild) is sampled once with all triggers listed,
  and its correction follows the (original, corrected) verdict
  pair, never the trigger list.
- cloud/audit_pushback.py::select_audit_sample is now only a
  record-shaped adapter over cloud/audit_sampling.py::select_sample
  (seed required, retired reason names critical_path-for-kinds
  and periodic_sample removed); AUDIT_SAMPLE_EVERY_NTH deleted.
- Correction: original never mutated, correction appended,
  corrector != signer enforced in audit_sampling when both names
  are supplied; gate effect pinned (correction to pass never
  unblocks by itself -- schedule/cancel-and-rerun, blocked until
  a new passing re-audit; correction to fail re-blocks at once).
  Track 3 / track 5 retrigger vocabularies documented as synonyms.
- Skill text (tightening 3 item 2 + correction paragraph)
  rewritten to the unified rule; new test file pins the
  boundaries (mandatory union, dedup, ceil incl. the 9-record
  case, seed reproducibility, golden-set construction under both
  sample vocabularies, adapter order/non-mutation, correction
  preservation on both tracks).
This commit is contained in:
host committed 2026-11-03 02:49:25 +00:00
1 parent 8006a6fcba
commit a433460343
5 files changed
+546 -60

No files matched your search

+166 -24
View File
@@ -11,9 +11,31 @@ pushback/rebuild counters, or the golden-set approval flow; it only
defines which audit cases a human must re-examine, and what happens
when that re-examination finds the audit wrong.
UNIFIED SAMPLING RULE (single rule; this module is canonical for
selection, ``cloud/audit_pushback.py::select_audit_sample`` is only
its record-shaped adapter -- there is no second rule):
The scope of "mandatory" comes from track 3 (#244): golden-task
records and rebuild / refreeze / escalation records. The drawing
mechanism comes from track 5 (#238): seeded random draws with ceil
rounding. Track 3's old deterministic "every 10th record" rule is
superseded and removed: a batch of fewer than 10 ordinary records
drew zero under it, and a position-known draw is predictable. The
rates below are TEST DEFAULTS (``DEFAULT_*``), not approved
production values; the production rates are still a user decision.
Mandatory 1.0 is a rule, not a tunable rate.
Sampling rules (all testable, none left to "regular review"):
1. Mandatory sampling (ratio 1.0, never skipped):
1. Mandatory sampling (ratio 1.0, never skipped). A case is
mandatory when ANY of these triggers holds (trigger order for
display and for the legacy single-trigger helper is golden,
rebuild, third-failure, refreeze, escalate):
- ``golden_task``: the case's task is in the human-approved
golden set (``task_id`` when present, else ``id``). A golden
task's records are mandatory whatever their kind -- an
ordinary pass verdict on a golden task is sampled, not just
its failures.
- ``rebuild``: any case whose audit decision was rebuild-from-
scratch (推倒重做). A rebuild destroys the old implementation
in the workspace, so its verdict must always be re-examined.
@@ -22,18 +44,63 @@ Sampling rules (all testable, none left to "regular review"):
was given one targeted continuation round, and still failed.
This is the exact boundary where the "one more round vs
rebuild" judgement is most error-prone, so it is always sampled.
- ``refreeze``: a contract/design re-freeze record.
- ``escalate``: an escalation record.
A near-complete third failure whose continuation round SUCCEEDED
is not mandatory (the judgement proved itself), and a
near-complete first/second failure is not mandatory either (the
threshold is the third failure, per the rebuild rule).
threshold is the third failure, per the rebuild rule). A
``blocked_quota`` record is NOT mandatory under this rule (it
is not in track 3's mandatory kind list); it is sampled only
through the random tiers below.
2. Random sampling of the rest, with the seed recorded:
- normal audit cases: default ratio 0.10;
- critical-path cases (``critical_path=True``): default ratio
0.50 -- critical paths get a higher rate, not a free pass.
The seed is part of the plan: a sample selected without a
recorded seed is not reproducible and therefore not auditable.
Selection is deterministic given (cases, ratios, seed).
- critical-path cases (``critical_path=True`` and NOT already
mandatory): default ratio 0.50 -- critical paths get a higher
rate, not a free pass. (Track 3's old ``critical_path``
reason label for mandatory kinds is retired: mandatory kinds
now carry their own trigger names, and ``critical_path``
means only this 0.50 random tier.)
Mandatory cases are removed from the random pools BEFORE
drawing, so they consume no random quota. The seed is part of
the plan: a sample selected without a recorded seed is not
reproducible and therefore not auditable. Selection is
deterministic given (cases, ratios, seed).
4. One pass, no double counting. Selection partitions every case
exactly once: mandatory (all its triggers listed, one sample,
one sampling entry) or random-critical or random-normal. A
record that is both a golden task AND a rebuild is sampled
ONCE, with ``triggers == ["golden_task", "rebuild"]``; its
correction, if any, is a single record whose retrigger follows
the (original, corrected) verdict pair, not the trigger list --
triggers decide selection only, never the correction action.
Two different records (e.g. a triage record and the later
rebuild record for the same task) are two samples, not a
double count: deduplication is per record, not per task.
5. Golden-set construction. The caller-supplied golden id set
must be built from human-approved, non-sample tasks only:
``build_golden_task_ids`` applies both vocabularies -- a task
counts only with ``human_approved_by`` set AND none of
``is_example``, ``sample=True``, or an id starting with
``sample-``. Track 3's per-task approver rule and track 5's
sample-exclusion rule are both preserved; neither alone is
sufficient.
6. Correction gate effect (shared with track 3 / wiring #247).
A sampling correction NEVER unblocks a merge by itself: a
correction to ``pass`` (a wrong block) schedules a re-audit
and the gate stays blocked until a new passing re-audit
conclusion exists; a correction to ``fail`` (a wrong pass)
re-triggers pushback and re-blocks at once. Vocabulary
synonyms for the same pair actions: track 3
``retrigger_pushback_and_reblock`` == track 5
``reopen_audit_and_pushback`` (wrong pass), and track 3
``schedule_reaudit`` == track 5
``cancel_pushback_and_rerun_audit`` (wrong block, where
"cancel" means cancel-and-rerun, never cancel-and-merge).
3. Golden-set approval is separate from sampling and is NOT
satisfied by sample files: ``filter_golden_tasks`` drops any task
@@ -81,33 +148,88 @@ _RETRIGGER = {
}
def mandatory_trigger(case):
"""Return the mandatory trigger name for ``case``, or None.
def mandatory_triggers(case, golden_task_ids=None):
"""Return ALL mandatory trigger names for ``case`` (possibly []).
``case`` fields used: ``decision``, ``failure_count``,
``root_cause`` (``"structural"`` / ``"near_complete"`` / other),
Trigger order: golden_task, rebuild,
third_failure_near_complete_still_failed, refreeze, escalate.
``case`` fields used: ``task_id`` (else ``id``) for the golden
check, ``decision`` / ``kind`` for rebuild / refreeze /
escalate, ``failure_count``, ``root_cause``
(``"structural"`` / ``"near_complete"`` / other),
``continuation_failed`` (bool).
"""
if case.get("decision") == "rebuild":
return "rebuild"
triggers = []
golden = set(golden_task_ids or [])
task_id = case.get("task_id") if case.get("task_id") is not None \
else case.get("id")
if task_id is not None and task_id in golden:
triggers.append("golden_task")
if case.get("decision") == "rebuild" or case.get("kind") == "rebuild":
triggers.append("rebuild")
if (case.get("failure_count", 0) >= 3
and case.get("root_cause") == "near_complete"
and case.get("continuation_failed")):
return "third_failure_near_complete_still_failed"
return None
triggers.append("third_failure_near_complete_still_failed")
if case.get("decision") == "refreeze" or case.get("kind") == "refreeze":
triggers.append("refreeze")
if case.get("decision") == "escalate" or case.get("kind") == "escalate":
triggers.append("escalate")
return triggers
def mandatory_trigger(case, golden_task_ids=None):
"""Return the first mandatory trigger name for ``case``, or None.
Legacy single-trigger view of ``mandatory_triggers``; new code
must use ``mandatory_triggers`` so a multi-trigger case is not
silently reported under one reason only.
"""
triggers = mandatory_triggers(case, golden_task_ids)
return triggers[0] if triggers else None
def build_golden_task_ids(tasks):
"""Build the golden task id list from candidate tasks.
A task counts only when it has a human approver
(``human_approved_by``) AND is not a sample/example under any
vocabulary: ``is_example``, ``sample=True``, or an id starting
with ``sample-``. Returns ids in input order, samples dropped
silently here (count them with ``filter_golden_tasks`` when a
dropped count must be reported).
"""
ids = []
for task in tasks or []:
if not isinstance(task, dict):
continue
task_id = task.get("id", "")
if task.get("is_example") or task.get("sample"):
continue
if str(task_id).startswith("sample-"):
continue
if not task.get("human_approved_by"):
continue
ids.append(task_id)
return ids
def select_sample(cases, seed, normal_ratio=DEFAULT_NORMAL_RATIO,
critical_ratio=DEFAULT_CRITICAL_PATH_RATIO):
critical_ratio=DEFAULT_CRITICAL_PATH_RATIO,
golden_task_ids=None):
"""Select the audit sample. Returns a plan dict.
Mandatory cases are always included. The remaining cases are
grouped into critical-path and normal, each shuffled with
Single pass, no double counting: mandatory cases (all their
triggers listed) are always included and removed from the
random pools before drawing. The remaining cases are grouped
into critical-path and normal, each shuffled with
``random.Random(seed + ":" + group)`` and truncated to
``ceil(ratio * group_size)`` (a group of 1 with any positive
ratio therefore contributes 1 -- a small group is never rounded
down to zero and silently unsampled). ``seed`` is required: an
unseeded selection cannot be reproduced on review.
``golden_task_ids`` is the human-approved golden set (see
``build_golden_task_ids``); without it no case is golden.
"""
if seed is None or seed == "":
raise ValueError("sampling seed is required: an unseeded "
@@ -116,9 +238,9 @@ def select_sample(cases, seed, normal_ratio=DEFAULT_NORMAL_RATIO,
critical = []
normal = []
for case in cases:
trigger = mandatory_trigger(case)
if trigger is not None:
mandatory.append((case, trigger))
triggers = mandatory_triggers(case, golden_task_ids)
if triggers:
mandatory.append((case, triggers))
elif case.get("critical_path"):
critical.append(case)
else:
@@ -138,7 +260,9 @@ def select_sample(cases, seed, normal_ratio=DEFAULT_NORMAL_RATIO,
"ratios": {"normal": normal_ratio,
"critical_path": critical_ratio,
"mandatory": 1.0},
"mandatory": [{"case_id": c.get("id"), "trigger": t}
"golden_task_ids": sorted(golden_task_ids or []),
"mandatory": [{"case_id": c.get("id"), "trigger": t[0],
"triggers": list(t)}
for c, t in mandatory],
"random_critical_path": [c.get("id") for c in sampled_critical],
"random_normal": [c.get("id") for c in sampled_normal],
@@ -203,7 +327,8 @@ def golden_approval_checklist(tasks, approver=None, approved_at=None,
"dropped_samples": filtered["dropped_samples"]}
def handle_sampling_result(case, sampling_verdict, corrected_verdict=None):
def handle_sampling_result(case, sampling_verdict, corrected_verdict=None,
corrector=None, original_signer=None):
"""Turn one human sampling result into a record entry + actions.
``sampling_verdict`` is ``"correct"`` or ``"incorrect"``.
@@ -211,13 +336,30 @@ def handle_sampling_result(case, sampling_verdict, corrected_verdict=None):
should have been issued) must be supplied; the retrigger follows
the ORIGINAL decision via ``_RETRIGGER``, or escalates when the
original decision is unknown. Returns the entry dict; the caller
appends it with ``append_audit_record``.
appends it with ``append_audit_record``. This function never
mutates ``case``: the original conclusion is preserved and the
correction lives only in the returned entry.
Corrector separation (track 3 rule, enforced here when both
names are supplied): ``corrector`` must differ from
``original_signer``. Gate effect (shared with track 3 / wiring
#247, stated here so the retrigger names cannot be misread):
a correction never unblocks a merge by itself -- a correction
to ``pass`` schedules a re-audit (``cancel_pushback_and_rerun_audit``
== track 3 ``schedule_reaudit``) and the gate stays blocked
until a new passing re-audit exists; a correction to ``fail``
re-triggers pushback and re-blocks at once
(``reopen_audit_and_pushback`` == track 3
``retrigger_pushback_and_reblock``).
"""
case_id = case.get("id")
original = case.get("decision")
if sampling_verdict not in ("correct", "incorrect"):
raise ValueError("sampling_verdict must be 'correct' or "
"'incorrect', got %r" % (sampling_verdict,))
if (corrector is not None and original_signer is not None
and corrector == original_signer):
raise ValueError("corrector must differ from original signer")
if sampling_verdict == "correct":
return {"case_id": case_id, "original_decision": original,
"sampling_verdict": "correct",