Skip to content
academia.sh

Lesson 21 / 21

Responsible Release

Measuring what the published number covers: the threshold 0.50 setup publishes a single recall number (0.7097), but per class the same defense spreads between 0.9583 and 0.2105, and the published number is 0.4992 above the weakest. A narrow system card ties 2 of nine commitments to a number, a wide card 6; the other 3 stay claims. This lesson closes this course and the AI Engineering curriculum, gathering twenty-one lessons in one table.

Published Updated

In this lesson

  • Measures how widely a single published average spreads per class.
  • Counts the measures a system card carries and shows that every measure it lacks remains a claim.
  • Gathers the baseline, defended setup and cost numbers of the twenty-one lessons in one table.
Contents

The previous lesson measured that the feedback loop cannot see the false alarm. So far all these numbers have stayed inside: the same team built the set, read the indicator and moved the threshold. A released system tells the outside where it will be used, what was measured and what happens if it is misused. This lesson measures that text: the numbers a system card carries, the numbers it does not, and what each missing number is. Commitments are named by class: usage limit, transparency item, misuse plan.

  • EM63. The records, classes, defense and commitment list are fictional. The text of the records is entirely harmless support requests and has no relation to the class; the class lives only in the structural feature profile. The set is 240 records, 93 harmful, 147 clean.
  • EM64. The published setup is the model filter, threshold 0.50.
  • EM65. The narrow card carries only two average numbers. The wide card adds the per-class recall, the resolution of the set, the records sent to a human and the covered share of the appeals.
  • EM66. A commitment is tied to a number if the measure it rests on is on the card; otherwise it remains a claim. Commitments whose measure this course never produced remain claims on both cards.
  • EM67. The resolution of the set: the recall step is 1/93 = 0.0108, the false block step is 1/147 = 0.0068; the step per class is the inverse of the class’s record count and rises to 0.1000 for a class of ten records. The second run keeps the record set and only renews the filter’s own draw with seed 20260219.

The Number the Card Carries

# FICTIONAL. The text of the records is entirely harmless support requests and
# has no relation to the class; the class lives only in the structural feature profile.
SEED, M32 = 20260218, 0xFFFFFFFF


def rng(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def next_value():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return next_value


def pick(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def trace_id(m):
    h = 2166136261
    for c in str(m):
        h = ((h ^ ord(c)) * 16777619) & M32
    return h


CLASSES = ["clean", "indirect_instruction", "hidden_field_request", "privilege_escalation",
           "source_spoofing", "corrupted_input"]
SOURCES = ["user", "retrieved_document", "tool_output"]
FEATURES = ["instruction_mode", "role_change_request", "hidden_field_name", "side_effect_tool_name",
            "source_stamp_mismatch", "unusual_stamp_distribution", "excessive_length"]
PROFILE = {
    "clean":                [0.06, 0.02, 0.05, 0.03, 0.02, 0.04, 0.05],
    "indirect_instruction": [0.88, 0.42, 0.10, 0.30, 0.35, 0.08, 0.12],
    "hidden_field_request": [0.35, 0.15, 0.86, 0.12, 0.10, 0.06, 0.08],
    "privilege_escalation": [0.30, 0.25, 0.12, 0.84, 0.14, 0.05, 0.07],
    "source_spoofing":      [0.22, 0.55, 0.08, 0.10, 0.82, 0.07, 0.06],
    "corrupted_input":      [0.05, 0.03, 0.04, 0.03, 0.06, 0.80, 0.62],
}
SOURCE_SHARE = {
    "clean":                [0.72, 0.20, 0.08],
    "indirect_instruction": [0.05, 0.70, 0.25],
    "hidden_field_request": [0.55, 0.30, 0.15],
    "privilege_escalation": [0.40, 0.35, 0.25],
    "source_spoofing":      [0.10, 0.60, 0.30],
    "corrupted_input":      [0.65, 0.20, 0.15],
}
TEXT = ["bu ayki fatura tutari gecen aya gore yuksek geldi",
        "sayac endeksi yanlis girilmis olabilir",
        "mahallede kesinti ne zaman bitecek",
        "tarife basamagimi ogrenmek istiyorum",
        "ariza kaydim icin ekip ne zaman gelir",
        "adres degisikligi nasil yapilir"]
RECORDS = []
for i in range(240):
    r = rng(SEED + 6151 * i)
    c = CLASSES[pick(r(), [0.62, 0.10, 0.07, 0.07, 0.07, 0.07])]
    source = SOURCES[pick(r(), SOURCE_SHARE[c])]
    feat = {o: (r() < p) for o, p in zip(FEATURES, PROFILE[c])}
    RECORDS.append({"no": i + 1, "class": c, "source": source, "features": feat,
                    "text": TEXT[int(r() * len(TEXT))],
                    "length": 40 + int(r() * 260)})


def harmful(k):
    return k["class"] != "clean"


WEIGHT = {"instruction_mode": 0.42, "role_change_request": 0.26, "hidden_field_name": 0.44,
          "side_effect_tool_name": 0.40, "source_stamp_mismatch": 0.38,
          "unusual_stamp_distribution": 0.30, "excessive_length": 0.12}
SOURCE_BONUS = {"user": 0.00, "retrieved_document": 0.18, "tool_output": 0.12}


def score(k, seed=SEED):
    p = sum(WEIGHT[o] for o in FEATURES if k["features"][o]) + SOURCE_BONUS[k["source"]]
    r = rng(seed ^ trace_id(k["no"]))
    return min(max(p + (r() - 0.5) * 0.20, 0.0), 1.6)


def model_filter(k, threshold=0.40, seed=SEED):
    return score(k, seed) >= threshold


def approval_gate(k, required=True):
    """A record carrying a side-effect tool request is asked of a human."""
    return required and k["features"]["side_effect_tool_name"]


def measure(records, decision):
    tp = fp = tn = fn = 0
    for k in records:
        flagged, actual = decision(k), harmful(k)
        if flagged and actual:
            tp += 1
        elif flagged and not actual:
            fp += 1
        elif not flagged and actual:
            fn += 1
        else:
            tn += 1
    precision = tp / (tp + fp) if tp + fp else 0.0
    recall = tp / (tp + fn) if tp + fn else 0.0
    return {"tp": tp, "fp": fp, "fn": fn, "tn": tn,
            "precision": round(precision, 4), "recall": round(recall, 4),
            "false_block_rate": round(fp / (fp + tn), 4) if fp + tn else 0.0}


THRESHOLD, SECOND = 0.50, 20260219             # deployed threshold , second run seed
published = measure(RECORDS, lambda k: model_filter(k, THRESHOLD))
second = measure(RECORDS, lambda k: model_filter(k, THRESHOLD, SECOND))
print(f"published single number: recall {published['recall']:.4f} , in the second run"
      f" {second['recall']:.4f} (band {second['recall'] - published['recall']:.4f})")
print(f"false block rate {published['false_block_rate']:.4f} and"
      f" {second['false_block_rate']:.4f}")
print("\nclass                 records  20260218  20260219  resolution")
class_recall = {}
for c in CLASSES[1:]:
    ks = [k for k in RECORDS if k["class"] == c]
    d = sum(model_filter(k, THRESHOLD) for k in ks) / len(ks)
    d2 = sum(model_filter(k, THRESHOLD, SECOND) for k in ks) / len(ks)
    class_recall[c] = d
    print(f"{c:<20} {len(ks):>8} {d:>9.4f} {d2:>9.4f} {1 / len(ks):>11.4f}")
lowest = min(class_recall, key=class_recall.get)
print(f"difference between the published number and the lowest class:"
      f" {published['recall'] - class_recall[lowest]:.4f} ({lowest})")

# ---- System card: the measures it carries. Every measure not carried remains a CLAIM.
NARROW = {"share of harmful blocked", "false block rate"}
WIDE = NARROW | {"per-class recall", "resolution of the set", "records sent to a human",
                 "covered share of false alarms"}
COMMITMENTS = [
    ("usage limit", "not used in the stated class", "per-class recall"),
    ("usage limit", "irreversible action needs approval", "records sent to a human"),
    ("usage limit", "not the sole basis of a result", "share of harmful blocked"),
    ("transparency item", "share of records wrongly blocked", "false block rate"),
    ("transparency item", "resolution of the measurement", "resolution of the set"),
    ("transparency item", "set the measurement was made on", "set coverage"),
    ("misuse plan", "share covered by appeals", "covered share of false alarms"),
    ("misuse plan", "delay in seeing a degradation", "indicator delay"),
    ("misuse plan", "number of untried classes", "uncovered class"),
]
sent = [k for k in RECORDS if approval_gate(k)]
print(f"\nnumbers added by the wide card: records sent to a human {len(sent)} , of them"
      f" {sum(harmful(k) for k in sent)} harmful ; set {len(RECORDS)} records ,"
      f" recall step {1 / 93:.4f} , false block step {1 / 147:.4f}")
print("\ncommitment class        commitment                           narrow card  wide card")
for kind, what, measure_name in COMMITMENTS:
    print(f"{kind:<23} {what:<36} {'number' if measure_name in NARROW else 'claim':<12}"
          f" {'number' if measure_name in WIDE else 'claim'}")
for name, card_set in (("narrow", NARROW), ("wide", WIDE)):
    present = sum(o in card_set for _, _, o in COMMITMENTS)
    print(f"{name} card: {present}/{len(COMMITMENTS)} commitments tied to a number ,"
          f" {len(COMMITMENTS) - present} remain claims")
published single number: recall 0.7097 , in the second run 0.7419 (band 0.0322)
false block rate 0.0544 and 0.0544

class                 records  20260218  20260219  resolution
indirect_instruction       24    0.9583    0.9583      0.0417
hidden_field_request       17    0.7059    0.7059      0.0588
privilege_escalation       10    0.8000    0.8000      0.1000
source_spoofing            23    0.8261    0.8261      0.0435
corrupted_input            19    0.2105    0.3684      0.0526
difference between the published number and the lowest class: 0.4992 (corrupted_input)

numbers added by the wide card: records sent to a human 27 , of them 24 harmful ; set 240 records , recall step 0.0108 , false block step 0.0068

commitment class        commitment                           narrow card  wide card
usage limit             not used in the stated class         claim        number
usage limit             irreversible action needs approval   claim        number
usage limit             not the sole basis of a result       number       number
transparency item       share of records wrongly blocked     number       number
transparency item       resolution of the measurement        claim        number
transparency item       set the measurement was made on      claim        claim
misuse plan             share covered by appeals             claim        number
misuse plan             delay in seeing a degradation        claim        claim
misuse plan             number of untried classes            claim        claim
narrow card: 2/9 commitments tied to a number , 7 remain claims
wide card: 6/9 commitments tied to a number , 3 remain claims

The Remaining Claim

The published single number is 0.7097, and it is hard to call it wrong: it is correct on the set. Per class, the same defense spreads between 0.9583 and 0.2105; the difference between the published number and the weakest class is 0.4992. “This system is not used in this class” is a usage limit, and the number that would verify it is only on the class row, not inside the average. The narrow card does not carry that row, so the sentence remains a claim.

The class row opens a second thing: The two-run band of the published number is 0.7097 to 0.7419, three resolution steps, and the whole band comes from the weakest class: corrupted input moves between 0.2105 and 0.3684 while the other four classes show zero difference.

Widening the card ties four more of the nine commitments to a number: the class row, the resolution, the 27 records sent to a human and the covered share of the appeals. The remaining three are covered by no card; that is the state of the measurement, not a flaw of the card. What the set the measurement was made on represents no measurement on that set can show. The delay in seeing a degradation came out as 45 and 220 records in two runs, so its band is wider than the delay. The number of untried classes can only be bounded by counting the tried ones; the share that passed for a class with no row in the report is not zero but unknown.

This is the course rule on the release side: where the published number is not written together with the set it covers, everything it does not cover is a claim.

Summary

  • The published average is 0.7097; per class the same defense spreads between 0.9583 and 0.2105, a difference of 0.4992.
  • The average’s two-run band is 0.0322, and the whole band comes from the weakest class; the other four show zero difference.
  • A class’s resolution is the inverse of its record count: 0.1000 for ten records, so even a row written to four digits cannot be read that finely.
  • Of the nine commitments the narrow card ties 2 to a number, the wide card 6; the other 3 have no measure: the set’s representativeness cannot be measured from inside, the indicator delay’s band is wider than the delay, and the untried class’s share is unknown.

Course Wrap-Up

The numbers measured over the course: The sign scheme is single: + shows that the defended setup’s number is higher than the baseline, − that it is lower, and neither says good or bad. Where rows share no unit, the measure follows the lesson name.

Lesson Undefended baseline Defended setup Cost
Prompt Injection — recall no filter 0.0000 rule filter 0.7957 (+0.7957) false alarms 0 to 23
Jailbreak Techniques — recall threshold 0.80: 0.4946 threshold 0.30: 0.9032 (+0.4086) false block rate 0.0068 to 0.1837
Data Exfiltration — requests stopped (35) no filter 0 full rule filter 25 (+25) added by masking 0, residue 1
Tool Misuse — harmful sent to a human no gate 0 approval gate 24 (+24) 3 unnecessary reviews, recall 0.2581
Training Data Poisoning — harmful share in the corpus no filter 0.3875 rule gate 0.1329 (−0.2546) 23 clean records lost
Model Inversion and Inference Attacks — hidden fields out no filter 106 four-name filter 0 (−106) clean replies losing a field 41
Adversarial Examples — recall on corrupted input rule filter 0.2632 rule with added flag 0.8421 (+0.5789) false alarms 23 to 30
AI Red Teaming — share that passes the defense narrow campaign 0.1000 93-trial coverage 0.2043 (+0.1043) selection band 0.0600, untried unknown
Input and Output Filters — precision rule filter 0.7629 rule and model stacked 0.7551 (−0.0078) false block rate 0.1565 to 0.1633, recall the same
Content Moderation — recall on corrupted input rule filter 0.2632 content moderation 0.8421 (+0.5789) false block rate 0.1565 to 0.2177
Personal Data Masking — records cleaned no masking 0 flag policy 32 (+32) tasks broken 23, 7 for a clean subscriber
Permissions and Sandboxing — harmful stopped undefended 0 read-only 62 (+62) tasks completed 1.0000 to 0.6667
Untrusted Content Marking — harmful neutralized no marking 0 marking 42 (+42) false alarms 0, 1 clean record lost its way
Actions Requiring Human Approval — harmful caught no gate 0 narrow gate 24 (+24) 3 unnecessary interruptions; reviews 4 at 0.20
Evaluation Set Design — precision (defense fixed) representative set 0.7629 borderline sample set 0.4444 (−0.3185) false block rate 0.7143
Automated Evaluation — agreement with human labels criteria-based 0.8250 model judge 0.8833 (+0.0583) 0 to 246 calls, 10779 tokens
Human Evaluation — agreement between evaluators three-level scale 0.7583 guideline with examples 0.9306 (+0.1723) unanimity accuracy 0.9126 to 0.8744
Regression Testing — recall of the judge format constraint in place 0.9570 constraint removed 0.7742 (−0.1828) calls 246 to 330, unreadable replies 0 to 31; false block difference exactly 0.0000
Production Monitoring — delay in seeing a degradation unreported without indicator proxy reports after 20 records 32 reviews in 300 records; labeled indicator 45 and 220
The Feedback Loop — covered share of false alarms channel closed 0.0000 narrow appeal channel 0.3750 (+0.3750) false alarms 8 to 27 in five rounds
Responsible Release — commitments tied to a number (9) narrow card 2 wide card 6 (+4) 3 commitments remain claims

The course’s rule is written in the table row by row: a defense whose blocked share and wrongly blocked share are not written together counts as unmeasured. With the cost column empty every row would read like a success; it does not, because we wrote it.

The second claim is read from the same table too: an added defense can make the work worse. The rows that say so by name: Input and Output Filters (one more clean record blocked, no new harmful one caught), Data Exfiltration (masking adds 0, at the cost of nine deleted fields), Tool Misuse (the source-widened gate takes forty-four clean reviews for nine harmful, precision 0.5586), Training Data Poisoning (the source gate raises clean record loss from 23 to 66 for an unmeasurable 0.0054), Content Moderation (the label falls on nine clean records, the defense stays below the baseline), Personal Data Masking (masking every record breaks 169 tasks), Permissions and Sandboxing (four of the eighteen added records are harmful, false block rate 0.2517), Actions Requiring Human Approval (a wider gate takes the caught from 24 to 17, interruptions to 23) and The Feedback Loop (false alarms 3.4 times, no new harmful one caught). In nine places the added layer made us pay for being added.

Differences below the resolution are written by name and are not findings: in Jailbreak Techniques, the one-record difference at threshold 0.30; in Data Exfiltration, the residue that falls to zero in the second run; in Training Data Poisoning, the 0.0054 below the 0.0106 step; in Adversarial Examples, 0.4737 versus 0.4211 inside the class; in Permissions and Sandboxing, one full step of 0.0068; in Actions Requiring Human Approval, the counts 22, 22, 23; in Automated Evaluation, the false block difference of 0.0068 and the class difference of 0.0588; in Production Monitoring, the indicator whose band is wider than its delay. None is zero, none is measured.

This wrap-up also closes the AI Engineering curriculum. The measurement axis of the seven courses gathers into one sentence: surface → prompt → call → retrieval → loop → contract → defense. Each course started where the previous one left off and wrote the cost of the layer it added. The curriculum’s rule one last time: an AI system’s number is not the model’s number but the setup’s number; a setup whose cost is not written counts as unmeasured.

Over one hundred and thirty-two lessons the setup was built around the model, each piece with its cost written. One thing was never asked: the data pipeline that feeds this setup. The record set was generated inside the lesson, the document vocabulary written by hand, the trace record kept in memory. Where this data comes from, how it runs in production and who learns when it breaks went unasked. The next curriculum, Data Engineering and MLOps, builds this pipeline beneath the setup and counts its cost too.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close