Skip to main content

Input Controls

Student Privacy

student-privacy finds student-record content in a request, such as a student ID or the word transcript. It replaces student ID phrases before the model sees them, or blocks the request. With the age gate on, it also blocks student records about a child under 13.

A redact verdict does not mean that all student information is gone. Only student ID phrases are replaced: a word such as transcript sets the verdict but stays in the text. The age check reads the message text only. It does not verify identity or consent.

Configuration​

policy-config.yaml
pack:
  name: student-privacy-example-1
  version: "1.0.0"
  enabled: true

policies:
  chain:
    - student-privacy

policy:
  student-privacy:
    action: redact
    age_gate: true

Verify the age gate with a pack test​

Add these cases to the file and run verdictan policy test --json:

Add to policy-config.yaml
testing:
  suites:
    - name: student-privacy
      cases:
        - name: blocks-under-13-student-record
          input: {messages: [{role: user, content: "Student ID: AB-1234 and age 12."}]}
          expected: {verdict: block, reason_code: student_privacy.age_gate}
        - name: redacts-student-id-age-13
          input: {messages: [{role: user, content: "Student ID: AB-1234 and age 13."}]}
          expected: {verdict: redact, reason_code: redact.applied}
        - name: redacts-transcript-only
          input: {messages: [{role: user, content: "Send the transcript."}]}
          expected: {verdict: redact, reason_code: redact.applied}
        - name: allows-clean-education
          input: {messages: [{role: user, content: "Help an age 12 learner with fractions."}]}
          expected: {verdict: allow, reason_code: ok}

All four pass. The last case shows that an age alone is not a match. With action: block, the marker cases are blocked with student_privacy.block instead.

The test runner checks the request only. Test response redaction, response blocks, and streaming through a gateway.

Fields​

FieldTypeDefaultDescription
actionredact or blockredactWhat happens to a match in the request. redact also redacts the response. block also turns on the response block check.
age_gatebooleanfalseA match together with an age from 1 to 12 in the text blocks the request

How it works​

  1. The gateway joins the request messages.
  2. It looks for the built-in terms at word boundaries and for the student ID phrase. See Input detection.
  3. With age_gate, it reads the first age expression and notes whether the age is from 1 to 12.
  4. No term or ID phrase: allow with student_privacy.clean. An age alone does not match.
  5. A match with an age from 1 to 12: block with student_privacy.age_gate.
  6. A match with action: block: block with student_privacy.block.
  7. A match with action: redact: redact with student_privacy.redact. The redaction pass then replaces student ID phrases before dispatch.
  8. The details record action, age_gate, under_13, student_id_like, and the first keyword_hit.
  9. When the provider responds, the gateway applies the output behavior of action. See Output behavior.

Input detection​

DetectorMatches
Built-in termsstudent id, student_id, transcript, iep, 504 plan, grade, gpa, disciplinary, ferpa
ID phrasestudent id, student identifier, or student number, an optional :, #, or -, then at least four letters, digits, or hyphens
Inline ageage N or N years old, with a one- or two-digit N

Case does not matter.

TextWith age_gate: falseWith age_gate: true
Help an age 12 learner with fractions.allowallow
Student ID: AB-1234redactredact
Student ID: AB-1234, age 12redactblock with student_privacy.age_gate
Send the transcript.redactredact

The age gate reads message text only. It does not use account profiles, headers, verified birth dates, or consent records, and it has no separate level for ages 13 to 17.

Output behavior​

With gateway 0.1.26 or later, the output behavior applies to streamed and buffered responses on Chat Completions, Responses, and Messages.

ConfigurationResponse
action: redactThe redaction pass replaces student ID phrases in the supported text fields. A changed response has a nested student_privacy.redact result and the top-level reason redact.applied.
action: blockA response that contains student id, studentid, student identifier, student number, studentnumber, transcript, or ferpa is blocked with student_privacy.block. student numbers does not match.

The nested redaction result names student-privacy only when the chain has no pii-detector, hipaa-phi-detector, or dlp-filter. See Output redaction reason codes.

A buffered response block returns HTTP 400 without the provider body. A streamed response block ends the stream with the error event of the route:

RouteError event
/v1/chat/completionsA data: event with the code content_policy_violation, then data: [DONE]
/v1/responsesA final event: error frame
/v1/messagesAn Anthropic event: error frame

In a stream, the gateway holds back text that can be the start of a blocked phrase. Thus the client does not get the phrase or the identifier after it. The request records the usage that the provider reports. See Output blocks in a stream.

Phase and verdicts​

ItemValue
Input phaseThe joined request messages
Output phaseRedacts ID phrases with redact, or blocks selected terms with block
Verdictsallow, redact, block
No matchstudent_privacy.clean
Redactionstudent_privacy.redact
Blockstudent_privacy.block
Age gate blockstudent_privacy.age_gate

Limits and failure behavior​

  • This is deterministic text matching. Legal, consent, identity, and retention controls need their own processes.
  • Only the student ID phrase is replaced. A term such as transcript gives redact with nothing to replace, and the text goes out unchanged. Check the forwarded payload.
  • The policy result does not list redaction targets. The redaction pass reports the replacements.
  • The response block check uses fewer terms than the request check: not iep, 504 plan, grade, gpa, or disciplinary.
  • The response block check runs only with block, and response redaction only with redact.
  • Request blocks happen before the provider call on every transport.
  • A stream that ends with student number or studentid is not blocked. Only that phrase gets to the client, with no identifier after it.
  • With two or more spaces between student and id, the text student can get to the client before a stream block.
  • grade and gpa appear in ordinary education text. Review false matches before rollout.
  • Combine with pii-detector or dlp-filter for other personal or institutional data.
ProblemCauseAction
A request with age 12 was allowedNo term or ID phrase matched, age_gate is off, or an earlier age expression set the age.Include a marker in the test and check the first age expression.
redact but the text did not changeOnly ID phrases are replaced.Use block, or add a dlp-filter pattern for the term.
A response with grade was not blockedThe response check uses fewer terms.Test with the documented output terms, or use another output control.
The control is not in the resultsIt is not in the effective chain, or a condition or target excludes it.Check the applied route chain and targeting.

Next steps​