AFP engineering series · Chapter 11 of 25

Integrate a screening service without confusing a successful API call with complete inspection or permission to act.

A screening service answers a bounded question

A managed screening service can inspect submitted material for configured risks. It does not automatically know the authenticated customer's entitlements, the remaining refundable balance, or whether a destination change was approved. Treat its result as one input to a decision pipeline, not as a universal permission token.

Google Model Armor documents prompt and response screening as well as explicit limitations, including independent single-turn inspection and unsupported encoded content. Check the current supported formats, endpoints, and request methods before implementation. The architecture below is a proposed integration pattern; it is not a claim that screening removes every jailbreak or fraud risk.

Put a coverage contract around every call

Define the object being inspected: raw user text, extracted document text, a tool result, or a completed model response. Include a content identifier, transformation version, policy template version, and required detector set. The adapter should return both the service result and a coverage statement that identifies unsupported or omitted material.

An HTTP 200 response means the request was handled at the transport layer. Your application still needs to inspect the service's result fields. A failed detector, unsupported payload, or partial inspection must not become a clean pass because the network call succeeded. Preserve these distinctions in metrics and in the user-facing fallback behavior.

Build a three-stage decision

StageQuestionExample outcome
CoverageWas all required material inspected?Unsupported image: review
Content policyDid inspected material violate a configured rule?Prohibited content: block
Business authorityMay this principal perform this exact action?Wrong order owner: deny

This ordering prevents a content pass from bypassing authorization. It also makes failures explainable. A user whose file format is unsupported should not be told that they violated policy. A user who lacks permission should not be told that a content detector failed. Stable reason categories help support and incident response distinguish those situations.

For high-impact actions, require all mandatory stages to complete successfully. For low-risk read-only tasks, a restricted fallback may be acceptable if the product explicitly defines it. Do not let the model select the fallback policy based on how urgently the user asks.

Normalize results in an application adapter

Illustrative python; adapt the persistence and identity adapters to your service.

def decide(screening, authorization):
    if not screening["coverage_complete"]:
        return "review_required"
    if screening["status"] != "completed":
        return "screening_unavailable"
    if screening["violation"]:
        return "blocked_content"
    if authorization != "allow":
        return "denied_action"
    return "allow"

# These are normalized application fields, not a Model Armor API schema.

Keep the normalization layer versioned and tested against recorded synthetic responses. Provider SDK changes can alter enum handling or error representations. Reject unknown values until they are deliberately mapped. Avoid a permissive default branch that returns allow when a new service result appears.

Do not log full sensitive payloads merely to debug the adapter. Store minimal request identifiers and sanitized diagnostics, with a separate restricted evidence path when an investigation requires original material. Verify the provider's data-handling configuration and your own logging settings independently.

Budget latency and dependency failures

A screening call adds network latency and can fail independently of the model. Set a deadline that fits the user journey, cap retries, and share the parent request's total time budget. A guardrail that retries indefinitely can become a denial-of-service amplifier.

Use circuit-breaker behavior carefully. Opening the breaker should select a documented restricted mode, not bypass screening for all traffic. Keep action tools disabled when a mandatory screening dependency is unavailable. For a public FAQ, the fallback might serve a curated static answer instead of invoking an unscreened generation path.

Test service semantics and application semantics separately

Use synthetic service-response fixtures for clean, violating, unsupported, timeout, and malformed cases. These tests validate your adapter without consuming provider calls. Separately, run a small controlled integration suite against the configured service to verify authentication, endpoint selection, policy templates, and actual result parsing.

Do not claim detector accuracy from adapter tests. Accuracy evaluation requires labeled content representative of the product, including benign security discussions and the languages you serve. Record false positives and false negatives separately from transport failures. A detector can be accurately integrated and still be unsuitable for a particular use case.

Worked adapter review: transport success with incomplete screening

A screening request returns successfully, but one required inspection result is unavailable. The original adapter maps any successful HTTP response to passed=true. That makes monitoring look healthy while the action pipeline operates without the required evidence. Fix the adapter by validating the result schema and evaluating each mandatory inspection status.

Create recorded synthetic responses for complete-clean, complete-violating, unsupported, service failure, and unknown enum values. For each, assert the normalized outcome and whether the action service is called. Unknown or incomplete results should follow the documented restricted path. Keep transport success as a separate metric so operations can distinguish a network outage from a semantic integration failure.

The team then adds retries. A timeout after submission causes the client to retry while the parent request also retries. Introduce one shared deadline and a bounded attempt count. Propagate the logical request identifier to the adapter. The screening result may be reusable for the exact same content and policy version if the service contract and privacy design permit it, but it must not be reused for changed content merely because the conversation is the same.

During rollout, shadow a new policy template against synthetic and consented evaluation data while the existing enforcement remains active. Review disagreements by category and legitimate task type. Do not disable backend authorization to make the shadow results easier to compare. The content layer and the action layer should remain independently observable.

Finally, simulate the service becoming unavailable for ten minutes. Payment proposals remain held; public help uses a curated static response. When the dependency recovers, held actions are revalidated against current approval and order state. This exercise proves that screening is integrated into a reliable workflow rather than attached as a best-effort API call whose errors disappear into a generic exception handler.

Roll out with a traceable policy version

Shadow a new screening configuration while existing protections remain enforced. Compare decisions by category and investigate disagreements before changing production behavior. Record which content and action decisions would change, rather than reporting only a single aggregate block rate.

After enforcement, monitor unsupported-format traffic, latency tails, and review volume. Keep a rollback path for a bad template version without disabling backend authorization. The useful guarantee is that the application knows what was inspected, handles uncertainty deliberately, and never treats a content-screening result as proof of ownership or consent.

Sources and implementation scope

Primary references checked October 15, 2026. Framework details follow the linked documentation; the Northstar cases, policy contracts, and test designs are original illustrative designs. Python snippets labeled illustrative are not complete production integrations. ADK package metadata checked for this series reported 2.12.0; pin and test the version used by your application.

Protect the action boundary with verified evidence, and test both containment and legitimate use.