Learning objectives
By the end of this module, you will be able to:
- Choose between gateway, middleware, and embedded verification
- Pass an explicit verification result into local enforcement
- Compose multiple verified constitutions without bypassing trust checks
- Define degraded operation from system risk, rather than from convenience
7.1 — Integration patterns
The reference SDK is a local library, so verification runs inside your own system and needs no hosted decision service. You still have to choose where in your system it runs. The three patterns below place it at a gateway, in middleware, or directly in application code.
Pattern A: Gateway boundary
A gateway verifies bundles and applies policy before a request reaches a model provider. This keeps trust configuration and audit controls in one place. The cost is that every request now depends on the gateway, so a compromise or outage there affects everything behind it.
Application
→ VCP gateway: load, verify, enforce, minimize
→ model provider adapter
→ response and audit evidence Pattern B: Application middleware
Middleware works well when every request to the model passes through a
single service you control. The example below assumes that bundle_repository and trust are application-owned dependencies:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from vcp import (
Orchestrator,
PDPEnforcer,
RefusalBoundaryPlugin,
VerificationResult,
)
app = FastAPI()
enforcer = PDPEnforcer(fail_closed=True)
enforcer.register(RefusalBoundaryPlugin())
@app.middleware("http")
async def vcp_middleware(request: Request, call_next):
if request.method != "POST":
return await call_next(request)
bundle = bundle_repository.for_request(request)
verification = Orchestrator(trust).verify(bundle)
if verification is not VerificationResult.VALID:
return JSONResponse(
status_code=403,
content={"error": "VCP verification failed"},
)
decision = enforcer.evaluate(
bundle,
content=(await request.body()).decode("utf-8"),
verification_result=verification,
)
if not decision.allowed:
return JSONResponse(
status_code=403,
content={"error": "VCP policy blocked request"},
)
request.state.verified_vcp_bundle = bundle
return await call_next(request) The example above does not cap the size of the request body. In production, set a limit before decoding it. Also keep sensitive policy evidence out of responses to callers, and make sure downstream handlers cannot swap the verified bundle for fresh, untrusted input.
Pattern C: Embedded library
Call the SDK directly at the point where a model prompt or tool action is authorized. This reduces infrastructure, while requiring every call site to preserve the same verification and enforcement sequence.
7.2 — Multi-constitution composition
Composition means combining several constitutions, such as an organization-wide one and a domain-specific one, into a single context for the model. Verify each bundle on its own first. Combining bundles never passes trust from one to another, so an unverified bundle stays untrusted even beside a verified one:
from vcp import (
Orchestrator,
VerificationResult,
format_multi_constitution_injection,
)
bundles = [organization_bundle, domain_bundle]
orchestrator = Orchestrator(trust)
for bundle in bundles:
result = orchestrator.verify(bundle)
if result is not VerificationResult.VALID:
raise PermissionError("Constitution set is not fully verified")
system_context = format_multi_constitution_injection(bundles) format_multi_constitution_injection lists the verified
constitutions in composition-layer order and marks higher layers as taking
precedence. It does not check whether their rules contradict each other.
Use the SDK's Composer when you need explicit CSM-1 semantic conflict
handling, for example when one constitution allows what another forbids.
Test ordering, precedence, strictness, and conflict behavior with your own
policy examples.
7.3 — Degraded operation
Degraded operation is what your system does when part of the verification chain is unavailable, such as an unreachable revocation endpoint or bundle store. A bundle that could not be verified is still rejected; the strategy decides what, if anything, runs without it. Group your actions into classes by the harm a wrong decision could cause, then choose a strategy for each class and document it before an outage:
| Strategy | Use | What it requires |
|---|---|---|
| Fail closed | Safety-critical, financial, medical, or irreversible actions | Deny when bundle, trust, revocation, scope, or verification evidence is unavailable |
| Verified cached bundle | Bounded offline operation | Previously verified bytes, valid time window, local trust state, replay controls, and an explicit maximum age |
| Restricted fallback | Low-risk availability paths | A separately reviewed capability subset with no high-impact actions |
| Audit-only mode | Observation or staged rollout | Clear user and operator indication that enforcement is not active |
A generic fail-open path lets requests through unchecked whenever verification cannot run. That is unsuitable for any control whose absence creates the very risk it is meant to limit.
7.4 — Error handling
verify_or_raise raises a VerificationError instead of returning a result, which suits code that already handles
failures with exceptions. The error carries the failed verification
result. The log below records that result's name and a fixed message,
never the bundle itself.
from vcp import VerificationError
try:
orchestrator.verify_or_raise(bundle)
except VerificationError as error:
logger.warning(
"VCP verification rejected bundle",
extra={"code": error.result.name},
)
return deny_response("Value verification unavailable") Do not log raw bundle content, context, keys, or user identifiers in the error path.
7.5 — Performance and capacity
- Benchmark verification, revocation lookup, context encoding, and provider latency separately
- Bound bundle size and context growth before cryptographic work
- Use the SDK's bounded replay and revocation caches
- Cache only exact verified bytes with trust and freshness metadata
- Measure latency for your own integration on representative hardware; the SDK makes no universal latency claim, so do not rely on one
Exercise
Test the Pattern B middleware with two bundles. The first has a
deliberately invalid signature; it must return INVALID_SIGNATURE and be denied. The second has an
unreachable revocation endpoint; it must return REVOCATION_UNAVAILABLE. The example denies every result
other than VALID, so add a branch for REVOCATION_UNAVAILABLE that applies your degraded-operation
policy. Confirm that neither bundle reaches the model and that each
action class follows the policy you documented for it.
See it in action
The Relay demo illustrates context handoff between agents. It is a scenario demonstration, not a benchmark or third-party conformance result.