Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Project: audit support resolution time and competing exits

Last updated: 5 Oct 20265 min read
project
IntermediateBy AITrove Editorial

Build an event ledger, verify tied-time risk sets, estimate day-six resolution and bounded open time, and separate cancellations from censoring.

Freeze a case-level cohort

Start with cases created during a documented enrollment window and follow each from creation to first resolution, cancellation, or extraction cutoff. Keep one case ID, queue, created timestamp, final event timestamp, terminal status and source-record version per row. Reject impossible negative intervals and duplicate IDs before analysis. If the extract includes only cases reaching a specialist queue, change the time origin or explicitly model delayed entry. Cohort entry is part of the estimand.

Make the event table reviewable

Use an eight-case single-outcome fixture first: durations and resolution flags (2,1), (3,0), (3,1), (5,1), (5,0), (8,1), (10,0), (10,1). The risk sets at distinct days are eight, seven, five, three and two. Check that each day removes exactly its resolutions and censors before the next day. The day-three event and censor share the same seven-case denominator. The event-table lesson supplies the accounting rule.

Reproduce the fixed-horizon metrics

Calculate unresolved shares of 0.875, 0.75 and 0.60 after days two, three and five. Day-six estimated resolution is 0.40, and restricted mean unresolved time through day six is 4.975 case-days. These are training-fixture values, not a production service claim. Capture the calculation code, denominator table, selected horizon and extraction cutoff in the project output. The bounded-time measure avoids inventing a distant tail.

Introduce cancellations deliberately

Create a second six-case ledger with one resolution at day two; one cancellation and one censor at day three; one resolution at day five; one resolution and one cancellation at day seven. Verify final cumulative resolution incidence 11/18 and cancellation incidence 7/18. Do not merge this fixture into the first one: it tests a different outcome policy. Explain why censoring cancellations in a resolution-only curve would answer a different question. Competing risks provides the accounting.

Write the release decision

The packet should contain cohort SQL or extraction logic, a status-code map, one-row-per-case checks, event table, unresolved curve, cumulative incidence by terminal outcome, common-horizon restricted mean, risk counts and a caveat on censoring. Compare queue groups only after checking their entry dates and follow-up maturity. If cancellation meanings shifted during collection or the day-six risk set is too thin, withhold the cross-queue comparison and document the repair needed.

Implementation

python
def support_resolution_audit(case_records, horizon_days):
    if len({case_id for case_id, _, _ in case_records}) != len(case_records):
        raise ValueError("duplicate case ID")
    day_counts = {}
    for case_id, day, outcome in case_records:
        if day < 0 or outcome not in {"resolved", "cancelled", "open"}:
            raise ValueError("invalid case record")
        day_counts.setdefault(day, {"resolved": 0, "cancelled": 0, "open": 0})[outcome] += 1
    at_risk = len(case_records)
    event_free = 1.0
    resolution_incidence = 0.0
    cancellation_incidence = 0.0
    open_days = 0.0
    previous_day = 0
    for day, counts in sorted(day_counts.items()):
        if day > horizon_days:
            break
        open_days += (day - previous_day) * event_free
        resolution_incidence += event_free * counts["resolved"] / at_risk
        cancellation_incidence += event_free * counts["cancelled"] / at_risk
        event_free *= 1 - (counts["resolved"] + counts["cancelled"]) / at_risk
        at_risk -= sum(counts.values())
        previous_day = day
    if previous_day < horizon_days and at_risk == 0:
        raise ValueError("no observed support through horizon")
    open_days += (horizon_days - previous_day) * event_free
    return resolution_incidence, cancellation_incidence, open_days

cases = [("R31", 2, "resolved"), ("R32", 3, "cancelled"),
         ("R33", 3, "open"), ("R34", 5, "resolved"),
         ("R35", 7, "cancelled"), ("R36", 7, "resolved")]
resolution, cancellation, open_days = support_resolution_audit(cases, 7)
assert round(resolution, 6) == round(11 / 18, 6)
assert round(cancellation, 6) == round(7 / 18, 6)
assert open_days > 0

Performance and operating cost

The ledger grouping pass is O(N) expected time and O(U) space; sorting U distinct days costs O(U log U), followed by an O(U) scan. A release build should also test timestamp ordering, status-code provenance and group-specific follow-up. These checks catch errors faster hardware cannot.

Common Mistakes

  • Do not reuse the single-event fixture as if its censors were known cancellations.
  • Do not publish a day-six queue comparison without sufficient follow-up in both queues.
  • Do not turn an unresolved status into a resolution event to make totals reconcile.

Read next

Continue the workflow: Project: audit specialist-queue resolution comparisons.

ai-data
data-science
Storage details