TECHNICAL NEWS & REPORTS

Intlight Tech Insights & Engineering Reports

HOMENews & Blog

A curated collection of deep-dive technical articles on Nuxt 4 architecture, Multi-Region Kubernetes, Zero-Trust WAF, Microservices, and Autonomous AI Agents.

AI AgentsTECHNICAL NEWS & REPORTS

Test What Your AI Agents Must Not Do

"A Guardrail Without A Negative Test Is Still An Assumption Most AI agent governance starts..."
B
Bobai KatoAuthor:
8/17/2026 6 phút
Test What Your AI Agents Must Not Do

title: "Test What Your AI Agents Must Not Do"
slug: "test-what-your-ai-agents-must-not-do"
summary: "AI agent guardrails need negative tests. Ota refusal canaries verify that the real execution boundary still rejects selected unsafe tasks and workflows before any work starts."
publishedAt: "2026-08-12T13:00:00Z"
category: "field-note"
status: "published"
author: "bobai"
otaVersion: "1.6.25"
cover_image: "https://res.cloudinary.com/ota-run/image/upload/q_auto/test-what-your-ai-agents-must-not-do.png"

tags:

  • aiagents
  • agentsafety
  • negativetesting
  • executiongovernance

A Guardrail Without A Negative Test Is Still An Assumption

Most AI agent governance starts with the positive path.

A repository tells an agent which task it may run. The agent invokes that task. The test suite
passes. CI goes green.

That proves one useful thing: the allowed path still works.

It does not prove that the forbidden path is still forbidden.

A stale allowlist, an incomplete dependency closure, a runner regression, or a hand-maintained CI
condition can quietly widen what an agent is able to execute. Every positive check may remain green
while the safety boundary has stopped doing its job.

This is why agent guardrails need negative tests.

Ota calls those tests refusal canaries.

They are available in Ota v1.6.25, and they reflect a deliberate product position:

Agent safety should be executable contract truth, not a promise that the model will remember to
behave.

Ota uses the same ota.yaml contract to define the safe task surface, evaluate the complete
selected closure, refuse unsafe execution, emit machine-readable evidence, and project the canary
into CI. There is no separate shell rule for the negative test to drift away from.

That is the difference between documenting a guardrail and operating one.

What A Refusal Canary Tests

A refusal canary names a task or workflow that must remain outside the repository's agent-safe
execution boundary.

For example, a repository may allow agents to run verification while reserving publishing for a
human-controlled path:

agent:
  safe_tasks:
    - verify
  refusal_canaries:
    - task: publish
    - workflow: release

tasks:
  verify:
    command:
      exe: pnpm
      args: [test]
    safe_for_agent: true

  publish:
    command:
      exe: pnpm
      args: [publish]
    safe_for_agent: false

workflows:
  release:
    intent: release
    run:
      task: publish

The positive check proves that the allowed lane remains callable:

ota run verify --agent

The refusal canary tests the opposite boundary:

ota run publish --agent --expect-refusal
ota up --workflow release --agent --expect-refusal

These commands do not run the unsafe task and then inspect its exit code. Ota exercises the same
agent admission boundary used by ordinary execution and requires refusal before the selected task,
its dependencies, or the workflow closure starts.

That distinction matters. The canary tests the execution boundary, not the behavior of a dangerous
command after it has already begun.

Expected Refusal Becomes A Passing Test

An ordinary agent refusal is a blocked execution result. That is the correct behavior for a direct
attempt to run an unsafe task, but it is inconvenient as a CI assertion because the shell sees a
non-zero exit.

--expect-refusal gives that result explicit negative-control semantics:

  • refused_as_expected means the declared agent-safety boundary refused the selected target before
    execution and the canary passes;
  • refusal_not_observed means the target was admitted, so the canary fails; and
  • wrong_refusal_boundary means execution was blocked for another reason, so the canary still
    fails.

The third state prevents an important false positive.

Suppose publish accidentally becomes agent-safe, but an unrelated organization policy still
denies the command. A weak negative test would see "something failed" and call the guardrail
healthy. Ota does not. The canary passes only when the safety boundary it was created to test is
the boundary that refused the lane.

For machine consumers, the same result is available as structured JSON:

ota run publish --agent --expect-refusal --json

The output carries the canary target, the runner-authored refusal record, whether execution
started, and the associated blocked receipt when refusal was observed. The agent does not
self-report that it behaved safely.

This is where Ota is intentionally more opinionated than a task runner. A task runner answers,
"Can I invoke this command?" Ota also asks, "Should this actor be admitted to this complete
execution closure, and what evidence should exist when the answer is no?"

Why This Must Run Through The Real Runner

It is easy to imitate a refusal canary with shell logic:

if [ "$AGENT_MODE" = "true" ]; then
  exit 1
fi

That only proves the shell condition still exists.

It does not prove that Ota's selected task closure, safety declaration, dependency expansion, and
execution admission agree. It can also drift independently from local execution, turning CI into a
second policy system.

A useful refusal canary has to pass through the same chokepoint as the real action. Otherwise the
test and the boundary can fail independently while both appear green.

Ota therefore derives the refusal from current contract truth at execution time. Authors declare
which task or workflow is the canary; they do not author the reason that should make it pass.

Put Refusal Canaries In CI

Local refusal gives agents and developers fast feedback. CI turns the same boundary into a
repository-level control.

A mature governance lane should test both directions:

  1. At least one meaningful safe verification path is admitted and completes.
  2. Each material unsafe path selected as a canary is refused by the agent boundary.

Ota's provider-neutral CI projection includes each declared refusal canary. The GitHub adapter
emits each one as its own provider check with a stable merge-check identity. That lets a repository
make the negative control merge-required instead of hiding several boundaries inside one opaque
script step.

This is stronger than one broad "agent safety" job. If the publish canary fails while verification
still passes, the provider shows exactly which execution boundary widened.

Branch protection remains provider-owned. Ota can generate and identify the GitHub check, but the
repository's GitHub policy must make it required if the organization wants a non-optional merge
gate. Future provider adapters must preserve the same ownership boundary rather than pretending
Ota controls provider policy.

What Refusal Canaries Prove

A passing refusal canary proves a narrow and valuable claim:

At this contract snapshot and runner boundary, the selected task or workflow was refused for the
expected agent-safety reason before execution started.

It does not prove:

  • that every dangerous repository action has been declared;
  • that the maintainer classified every task correctly;
  • that raw shell execution outside Ota is impossible;
  • that CI branch protection requires the canary check;
  • that runtime filesystem, network, credential, or provider controls were enforced; or
  • that the repository is globally safe for autonomous operation.

Those are different obligations.

Contract-claim assurance can evaluate whether observable repository evidence supports a declared
safety claim. Sandbox and capability providers can enforce runtime controls. CI policy can make
checks mandatory. Refusal canaries test whether one declared runner boundary still refuses what it
is supposed to refuse.

Keeping those claims separate is what makes the result trustworthy.

Turn Incidents Into Permanent Negative Tests

A refusal canary protects a boundary the repository has already identified. It cannot protect an
omitted path merely because that path reaches a similar outcome.

If publish is refused, Ota has proved that the selected publish closure was refused. It has not
proved that another task, migration, helper script, or raw shell command cannot reach the same
external effect. Presenting task-level refusal as effect-level protection would turn a precise
negative test into a broader claim the evidence does not support.

The practical operating model is a ratchet: when an incident or review exposes another material
execution path, add that real task or workflow as a permanent canary. The incident should improve
the executable governance suite, not remain only in a retrospective document.

Ota's current refusal canaries are task- and workflow-bound. Effect-level assurance across
equivalent execution paths is a separate, planned governance boundary; it is not something this
feature claims to provide today. Until that boundary is implemented and pressure-tested, canary
coverage should remain explicit about which declared lanes it exercises and which equivalent paths
remain unproved.

Choosing Useful Canaries

Do not turn every non-agent-safe helper into a canary. Choose actions whose accidental admission
would materially weaken the repository's governance story.

Good candidates include:

  • package publishing and release workflows;
  • production deployment;
  • destructive database operations;
  • credentialed external mutations;
  • infrastructure apply or teardown tasks; and
  • expensive or metered execution that should require a different authority path.

The canary should name the real contract task or workflow. Do not create a fake unsafe command
whose only purpose is to be refused; that proves the fixture, not the material repository boundary.

Also keep the positive lane. A system that refuses everything is not safely governed execution. It
is unavailable software. The useful result is selective admission: routine work remains easy, and
materially different work remains outside the agent-safe closure.

Try It In Your Repository

The fastest way to understand refusal canaries is to make one fail deliberately on a temporary
branch.

First, install Ota, then inspect the repository before changing its
contract:

ota doctor
ota tasks --use
ota tasks --safe --use

Add one real unsafe task or workflow to agent.refusal_canaries. Choose publishing, deployment,
infrastructure mutation, or another material lane that already exists in the repository. Then
validate both directions:

ota validate
ota run verify --agent
ota run publish --agent --expect-refusal --json

Now temporarily make publish agent-safe. The positive verification lane can remain green, but the
refusal canary changes to refusal_not_observed and exits non-zero. That is the failure shape the
feature exists to expose: the repository still works, but its agent execution boundary has widened.

When the local contract is correct, inspect the provider-neutral CI projection:

ota ci projection \
  --workflow verify \
  --mode native \
  --target-os linux \
  --json

For GitHub Actions, Ota can render the governed reusable workflow from that projection:

ota ci github render \
  --workflow verify \
  --mode native \
  --target-os linux

The repository keeps ownership of triggers, permissions, secrets, runners, environments, and
branch protection. Ota owns the contract-derived execution and refusal checks. That boundary lets
teams adopt Ota without replacing their CI provider or creating another hand-maintained workflow
language.

The Larger Point

AI governance cannot stop at telling agents what they may do.

It also needs tests for what they must not be allowed to execute.

Positive tests prove that an allowed path still works. Refusal canaries prove that a selected
forbidden path still stops at the runner boundary. Together they turn an agent allowlist from
static metadata into executable governance.

That is the standard Ota is building toward: boundaries that are declared once, exercised through
the real chokepoint, and retained as evidence rather than trusted as prose.

If your repository already tells agents what they may run, the next useful question is simple:

Which one unsafe action would you want CI to prove they still cannot run?

Go Deeper


Originally posted here: https://ota.run/blog/test-what-your-ai-agents-must-not-do


🔗 Nguồn bài viết gốc: Bobai Kato

Discussions & Comments15

Leave a Technical Comment

Share your architectural thoughts or ask technical questions...

L
Lucas MoreauCloud Native Developer
12 hours ago

Kafka event streaming with schema registry ensures backward compatibility even as payload models evolve across microservice boundaries.

A
Alexander WrightPrincipal Systems Architect @ Stripe
20 mins ago

Superb architectural breakdown! The hybrid L1 in-memory + L2 distributed Redis cache pattern is crucial for mitigating high-concurrency thundering herd issues.

D
David ChenStaff Infrastructure Engineer
12 mins ago

Totally agree, Alexander. Pairing that with singleflight request deduplication on the backend virtually eliminates DB spikes.

J
Julian SterlingCybersecurity Director
2 hours ago

Zero-Trust microsegmentation powered by eBPF and Cilium eliminates sidecar proxy overhead while delivering strict L7 network encryption. Excellent walkthrough!

O
Oliver BennettVP of Engineering
8 hours ago

Top-tier technical writing. Clear architecture diagrams, reproducible benchmarks, and actionable code snippets. Bookmarked for our engineering team.

K
Kenji SatoPrincipal Infrastructure Architect
2 days ago

Intlight's multi-region architectural blueprints set the benchmark for ultra-resilient, enterprise-grade cloud systems in 2026.

SPOTLIGHT & LATEST NEWS

Hot Trending Topics

View All →
I Thought I'd Lost the Plot. I Was Writing It. 🔥 HOT SPOTLIGHT
AI Agents6 min read

I Thought I'd Lost the Plot. I Was Writing It.

I Thought I'd Lost the Plot. I Was Writing It. I set out to build autonomous...

Explore
What Is the Circuit Breaker Pattern? A Practical Guide 🔥 HOT SPOTLIGHT
Microservices6 min read

What Is the Circuit Breaker Pattern? A Practical Guide

What Is the Circuit Breaker Pattern? A Practical Guide for Developers Imagine your...

Explore
I attacked my own npm package before launching it. It let the proposer approve their own writes 🔥 HOT SPOTLIGHT
Security6 min read

I attacked my own npm package before launching it. It let the proposer approve their own writes

My library exists so a human approves an LLM's UPDATE before it runs. It never checked that the approver was somebody other than the proposer — and wrote \"approved\" into the audit trail anyway.

Explore
Build an MCP Server in Go (Part 1): Designing a diagnostic-grade Kubernetes client 🔥 HOT SPOTLIGHT
Kubernetes6 min read

Build an MCP Server in Go (Part 1): Designing a diagnostic-grade Kubernetes client

This post designs the Kubernetes client. The next post wraps it as an MCP server and wires it to an...

Explore
The Write Policy Is the Hard Part: Promotion Pipelines for Agent Memory 🔥 HOT SPOTLIGHT
AI Agents6 min read

The Write Policy Is the Hard Part: Promotion Pipelines for Agent Memory

Storing agent memory is easy. Deciding what earns a permanent write, and keeping the write-path alive through RBAC and network policy, is the real work.

Explore
I Changed How I Think About AI Memory 🔥 HOT SPOTLIGHT
AI Agents6 phút

I Changed How I Think About AI Memory

I Changed How I Think About AI Memory When I first built Lean AI Memory, I focused too...

Explore
Real-Life Refactoring Example: ~3x Less Code to Read 🔥 HOT SPOTLIGHT
Microservices6 phút

Real-Life Refactoring Example: ~3x Less Code to Read

There is a popular idea that refactoring is making code shorter. It is not entirely wrong....

Explore
The Tragedy of the Clean-Handed Auditor 🔥 HOT SPOTLIGHT
Security6 phút

The Tragedy of the Clean-Handed Auditor

\"I could save them if they'd only listen...\" Hey, you. Yeah, you: the compliance or governance...

Explore
Related Articles6 articles
View all AI Agents →
I Thought I'd Lost the Plot. I Was Writing It.6 min read
AI Agents8/17/2026

I Thought I'd Lost the Plot. I Was Writing It.

I Thought I'd Lost the Plot. I Was Writing It. I set out to build autonomous...

Author: Joe BlackRead Article
The Write Policy Is the Hard Part: Promotion Pipelines for Agent Memory6 min read
AI Agents8/17/2026

The Write Policy Is the Hard Part: Promotion Pipelines for Agent Memory

Storing agent memory is easy. Deciding what earns a permanent write, and keeping the write-path alive through RBAC and network policy, is the real work.

Author: GuatuRead Article
I Changed How I Think About AI Memory6 phút
AI Agents8/17/2026

I Changed How I Think About AI Memory

I Changed How I Think About AI Memory When I first built Lean AI Memory, I focused too...

Author: Phúc PhùngRead Article
FastMCP Agent Mail: RBAC Tokens vs Anonymous Access, and the 403 Errors in Between6 phút
AI Agents17/8/2026

FastMCP Agent Mail: RBAC Tokens vs Anonymous Access, and the 403 Errors in Between

Why a FastMCP agent mail server that works anonymously in dev returns 403 behind TLS ingress, and how to wire bearer tokens without leaking them.

Author: GuatuRead Article
The Coordinated Rename Is the Agent's Most Dangerous Refactor6 phút
AI Agents17/8/2026

The Coordinated Rename Is the Agent's Most Dangerous Refactor

Multi-agent rename tooling rewrites two hundred files in ten seconds because it noticed the drift. Half the time the drift was a load-bearing distinction the team encoded on purpose. Vocabulary curation is a real-time review surface now, and senior includes refusing changes that would be technically more consistent because the domain has two concepts the agent has no way to see.

Author: Travis FrisingerRead Article
Test Deletion Is a Privileged Operation6 phút
AI Agents17/8/2026

Test Deletion Is a Privileged Operation

The cheapest way for an agent to make a failing test pass is to delete it. That is logical for the agent and catastrophic for the codebase. Tests are append-only by default. Deletion needs a human author, a separate commit, and a separate review.

Author: Travis FrisingerRead Article