Engineering Practice
The Validation Harness Is the Trust Boundary
Generated or automated changes are only as trustworthy as the independent checks that can falsify them.
- Testing
- Validation
- Automation
- System Design
- Risk Management
Generated or automated changes are only as trustworthy as the independent checks that can falsify them. A validation harness isn’t a nice-to-have polish; it’s the boundary between a change you can reason about and one you have to hold your breath around.
When you use a tool, agent, or generator to make changes—whether that’s infrastructure code, database migrations, configuration patches, or anything in between—you’ve delegated decision-making to something that isn’t you. That’s powerful. It’s also risky. The harness is where you get your confidence back. It’s the independent observer that says: “I don’t trust the generator, I trust this check.”
Independence Is Everything
The generator produces a change. The harness must not use the generator’s own logic to verify it. That’s a closed loop. You’ve just hidden the bug inside a circle.
If a DSL generates Terraform code, the harness doesn’t run the same DSL interpreter and compare outputs. It reads the Terraform directly and validates it against the original intent: “Is the resource count what we expect? Are the tags correct? Will this apply without errors?” It catches errors the DSL author couldn’t imagine because it asks different questions.
If an agent writes a SQL migration, the harness doesn’t run the agent again in test mode. It validates the migration directly: Does it follow naming conventions? Does it include rollback logic? Will it work on production’s dataset shape, not just empty tables? Can it complete within the maintenance window?
The moment your harness depends on the generator’s assumptions, you’ve licensed yourself to fail in ways you can’t audit. Independence means you’re asking the same question twice, in two different ways, from two different angles. The harness sees the finished product with fresh eyes.
Positive and Negative Tests Have Different Jobs
Positive tests check that the harness accepts what it should. Negative tests check that it rejects what it shouldn’t.
Build both, because they’re catching different kinds of failure:
- Positive: A correctly generated change passes all checks. This builds confidence in your harness itself. If a known-good change fails, your harness is too strict or has a bug.
- Negative: A malformed or dangerous change fails validation before it can run. This is the actual job. Without negative cases, you’re only testing that your harness doesn’t interfere with the happy path.
Negative cases are where most harnesses are weak. It’s tempting to skip them because they’re work: you have to invent plausible failures, mutations, and edge cases. But these are the tests that catch the generator producing code that compiles but shouldn’t run. A missing WHERE clause. A permission grant that’s too wide. A schema change that invalidates an index. A configuration that looks right but uses the wrong default.
Design negative test cases by thinking about failure modes of the generator itself. What if it misunderstood the intent? What if it made a copy-paste error? What if it applied a template that’s obsolete? Write a harness check for each one.
Capture Evidence, Not Just Pass/Fail
When a harness rejects a change, the generator or operator needs to know why. “Failed validation” is not debugging. “Failed validation: tag ‘owner’ is missing from resource type ‘aws_iam_role’” is actionable.
Capture:
- The exact condition that failed.
- The value or state that triggered the failure.
- The context: which resource, which line, which rule.
- Guidance on how to fix it (when that’s deterministic).
Your harness output is the contract between the validation system and the person who has to respond. Make it specific enough that they can fix the problem without reading the harness source code.
Also log what passed, not just what failed. If you’re generating 500 resources and 497 pass while 3 fail, you need to know which 497 did, so you can verify that the passing cases are actually correct and not just undersupported by your validation.
What the Harness Cannot Prove
A validation harness is bounded. It cannot prove:
- Behavioral correctness across the whole system: A resource can be syntactically valid, permission-wise safe, and properly tagged, but still incompatible with the rest of the infrastructure. A harness can validate schema and policy. It cannot simulate all interaction paths.
- Performance or scale: A generated configuration might be valid but inefficient, or valid at small scale but brittle at production scale. Validation catches errors; it doesn’t guarantee optimization.
- Operator intent: The harness can verify that a change matches a rule. It cannot verify that the rule itself was the right rule, or that it matches what the human actually wanted.
- External dependencies: If the generator depends on a service, API, or dataset that’s stale or offline, the harness can’t know. It can only validate what it can observe.
- Time-based or ordering failures: A migration might be syntactically correct but fail because it assumes an earlier step already ran, or because it times out under real load, or because another concurrent change conflicts with it.
A harness that claims to prove these things is setting you up to be surprised. Scope your harness to what it can actually check: shape, policy, naming, syntax, coverage, and measurable constraints. Leave the rest to integration testing, staging, dry runs, and monitoring.
A Validation Checklist
When designing a harness, work through this sequence:
- Identify the generator: What produces the change? What are its success and failure modes?
- Name the trust boundary: What must be true before this change is safe to apply?
- Write negative cases: Invent five plausible errors the generator might make. Write a test for each.
- Design positive cases: Write tests that known-good changes must pass.
- Capture specific failures: Each validation rule must produce actionable output.
- Scope the harness: List three things this harness will never prove. Write that down.
- Test the harness: Use it on changes from outside the team. Does it reject what it should? Does it accept what it should?
- Automate the harness into the change flow: If validation is manual or optional, it won’t run when you need it.
- Version the harness with the generator: Changes to the harness rules should be tracked. Validation rules are policy; they drift.
- Review harness failures in postmortems: If a bad change got through, ask: did the harness miss it, or did it pass and we ignored it?
The Generator Is Now Your Responsibility
Once you ship a generator—even if it’s a template, a script, or an agent—you’re responsible for its output. The harness is how you scale that responsibility. Without it, every generated change is a hand-signed voucher for a system you didn’t read.
With a harness, you’re saying: “This change is only trusted because I verified it independently.” That’s honest. That’s how you keep generators from becoming liability amplifiers.
The harness itself can fail—it can be too strict or too loose, miss edge cases, or drift out of sync with the system it’s validating. But at least now you have a measurable boundary. You can audit the harness. You can test it. You can argue about whether it’s right. You can’t do any of those things if validation is implicit or manual.
Start with one generator and one harness. Make that relationship work. Then scale it to the rest.