Attest: an ADK agent that audits what other models say about SEC-registered advisers A developer built Attest, an ADK-based agent that audits what AI models say about SEC-registered advisers against their Form ADV filings, for the All Things Agentic Hackathon. The agent runs a monthly battery of factual questions, scores answers against ground truth, and appends results to a hash-chained archive on Google Cloud. It uses three different Gemini models and encountered a Model Armor permission issue during development. A machine is describing your business to prospects several times a day, and there is no record of any of it. That was the whole starting point. I built Attest for the All Things Agentic Hackathon https://allthingsagentichackathon.devpost.com/ , Fortified Enterprise Fleet track, and I wrote this post for that hackathon too. Code is at github.com/jpka/attest https://github.com/jpka/attest . The problem is narrow on purpose. The SEC's 2026 examination priorities name AI in several places, including whether a firm's claims about its own AI are fair and accurate. That is the regulator checking what you say about your AI. Nothing there reaches the other direction. Whether an investment adviser has any liability for what somebody else's model says about them is open law, and I am not claiming otherwise. The narrow version is enough to build on. You are being described by a system you do not control, you have no record of it, and examiners are already asking firms about AI. Attest runs a fixed battery of factual questions about SEC-registered advisers on a schedule, scores each answer against the firm's Form ADV Part 1A filing, and appends the result to a hash-chained archive. Cloud Scheduler fires the monthly job onto a Pub/Sub topic. An authenticated push subscription delivers it to the agent on Cloud Run, and the agent works through the battery firm by firm. Six tools do the work: two read ground truth, one scores, one appends evidence, and two handle per-firm memory. The scorer slices the ADV record down to the question's category and returns a verdict, a rationale, the rubric version, the model that produced the verdict, and the guardrail screening record for that answer. Every archive entry carries the payload hash, the previous entry's hash, a sequence number, a timestamp and the model ID. The chain tail advances inside a Firestore transaction, and the payload lands in Cloud Storage afterwards with a generation precondition, so a replay cannot overwrite an entry. The agent cannot supply the previous hash. The archive is deliberately not the memory. Vertex AI Memory Bank holds semantic, mutable, per-firm findings. The archive is append-only, and nothing running on the agent can purge it. | Service | Role | |---|---| | Cloud Run | Hosts the orchestrator agent, min 0 max 3, traces to Cloud Trace | | Pub/Sub | Run topic plus an authenticated push subscription, 600s ack, backoff 60s to 600s | | Cloud Scheduler | Monthly job at 0 6 1 UTC | | Firestore | Registry roster and the chain tail | | Cloud Storage | One object per evidence entry, written with ifGenerationMatch=0 | | Vertex AI | Subject model from global , Memory Bank engine in us-central1 | | Model Armor | sanitizeUserPrompt on every captured answer before it reaches the scorer | | Cloud Trace | Every tool call is a span, 19 to 20 spans for a normal run | The agent is built on the Google Agent Development Kit ADK and runs on Cloud Run rather than Agent Engine, which mattered later. Three different Gemini models run here on purpose. The orchestrator and the subject model are gemini-3.5-flash-lite . I hold the scorer one version back at gemini-3.1-flash-lite , because a grader that is the same model as the subject is grading its own output. That version is also what my pre-build experiment graded with, so the old numbers stay comparable to what the deployed scorer produces. On Aug 20 the guardrail work died on 403 PERMISSION DENIED, write access to project was denied while creating a Model Armor template. The same credential wrote to Vertex AI successfully in the same session. Two observations, both pointing the same way. This API refuses writes, that one accepts them, so the service account is missing a role. I formally descoped Model Armor and started drafting the paragraph explaining its absence. It was the endpoint. Model Armor is served from a per-region host, modelarmor.