1Responsible Use and Verification of AI-Generated Code
▶
Artificial intelligence coding assistants have become genuinely useful tools in engineering practice. They can draft functions, suggest algorithms, and produce syntactically correct code in seconds. But speed and syntactic correctness are not the same as physical correctness, dimensional consistency, or engineering safety. This gap between looking right and being right is the central challenge engineers face when incorporating AI-generated code into professional or academic work. Understanding why verification is non-negotiable, and knowing exactly how to perform it, is one of the most important practical skills an engineer can develop in this era of AI-assisted programming.
Why Verification Is Non-Negotiable in Engineering
AI coding tools are trained on enormous corpora of text and code. Their fundamental objective during training is to predict the next plausible token — a word, a symbol, a variable name — given everything that came before. This means they are extraordinarily good at producing output that looks like correct code. They have absorbed patterns from thousands of textbooks, Stack Overflow answers, GitHub repositories, and worked examples. The result is code that reads fluently and follows recognizable conventions.
The problem is that plausibility is not the same as correctness. An AI tool has no internal model of the physical world. It does not reason about whether a pressure value makes sense for a hydraulic system, whether a stress result exceeds a material's yield strength, or whether a numerical method converges for the problem at hand. It pattern-matches. When a pattern from a slightly different engineering domain is the closest match in its training data, the tool will produce that pattern — and it will do so with exactly the same confident formatting as it uses when it is correct.
A concrete example illustrates the danger. Suppose you ask an AI assistant to write a Python function to compute the Reynolds number for flow in a pipe. The tool might produce something like:
def reynolds_number(velocity, diameter, density, viscosity):
return (density * velocity * diameter) / viscosity
This is correct. But if you ask for a slightly different context — say, the Nusselt number correlation for turbulent pipe flow — the tool might confidently return the Dittus-Boelter equation with an exponent that applies to cooling rather than heating, or a correlation valid only for Prandtl numbers in a range not applicable to your fluid, with no warning whatsoever. The code will run without error. The numbers will look reasonable. Only a reviewer who knows the domain will catch it.
Beyond the technical dimension, there is a professional accountability dimension. Engineers are licensed and ethically obligated to ensure that the work they produce is correct and safe. Professional engineering codes of ethics do not contain exceptions for errors introduced by software tools. If a structural calculation contains a wrong formula because the engineer copied AI-generated code without verifying it, the professional liability belongs to the engineer, not to the AI company. This is not a hypothetical concern — it is the same principle that has always applied to engineers using any computation tool, from slide rules to spreadsheets to finite element packages. The tool does not bear responsibility; the practitioner does.
For students in engineering programs, the same logic applies at the academic level. Submitting a calculation or program that contains an error you never detected because you did not verify the AI's output is not a minor slip — it signals that you have not yet developed the engineering judgment the course is trying to build. Verification is therefore not an optional quality enhancement layered on top of the "real" work. It is the real work.
Hand Calculation Verification
The most direct and reliable way to verify AI-generated engineering code is to solve a representative problem by hand first, before running the code. This practice forces you to engage with the underlying physics or mathematics independently of the tool, which is exactly the kind of engagement that builds genuine understanding.
The process is straightforward in principle. Choose a set of inputs for which you can calculate the correct output using a textbook formula, a worked example, or basic dimensional analysis. Work through the calculation carefully, keeping track of units at every step. Write down your expected result. Then run the AI-generated code on those same inputs and compare.
Consider a function that computes the deflection at the midpoint of a simply supported beam with a central point load. The formula from structural mechanics is:
delta = (P * L**3) / (48 * E * I)
where P is the applied load, L is the span, E is the modulus of elasticity, and I is the second moment of area. Before running any code, you should select specific numerical values — say, P = 10 000 N, L = 4 m, E = 200 × 10⁹ Pa, I = 8.33 × 10⁻⁶ m⁴ — and compute the deflection by hand:
delta = (10000 * 4**3) / (48 * 200e9 * 8.33e-6)
= (10000 * 64) / (48 * 1666000)
= 640000 / 79968000
≈ 8.00e-3 m (approximately 8 mm)
If the AI-generated function returns a value of 0.008 m for these inputs, you have strong evidence that the formula is correct. If it returns 0.8 m or 8 × 10⁻⁵ m, something is wrong — possibly a units mismatch, a misplaced constant, or a wrong formula entirely — and you must investigate before proceeding.
It is important to verify more than one test case. A formula with a transposed factor might give the right answer for one specific combination of inputs by coincidence. Testing at least two or three cases with different magnitudes and ratios significantly reduces this risk. You should also test cases where you can reason about the direction of the result even if you cannot compute it exactly — for instance, doubling the load should double the deflection in a linear elastic problem.
The hand-calculation verification should be documented and included in your project files. A brief note in a comment block, a separate verification document, or a dedicated section in a lab report all serve this purpose. This documentation creates an audit trail: if a result is ever questioned, you can demonstrate that you did not simply trust the code blindly.
Code Review Practices for AI-Generated Code
Hand calculation checks the numerical output. Code review checks the implementation itself. Both are necessary because a bug can produce correct results for the test cases you chose while failing for others.
The first rule of reviewing AI-generated code is simple but frequently ignored: read every single line before integrating the code into your project. This sounds obvious, but the fluent, confident style of AI output makes it psychologically easy to skim. Resist that temptation. Read as if you wrote the code yourself and are proofreading it for submission.
As you read, check the following systematically:
- Variable names and their physical meaning. Does a variable named
vrepresent velocity in m/s, or volume in m³? AI tools sometimes reuse common single-letter names in ways that clash with the conventions of your specific problem. Make sure every variable name is unambiguous in context, or rename it. - Units consistency. This is one of the most common sources of subtle errors. A formula that mixes SI and imperial units, or that uses diameter where radius is expected, will produce plausible-looking but wrong numbers. Check the units of every input and every intermediate calculation.
- Formula fidelity. Compare each formula in the code to the source — a textbook, a standard, a course handout. Do not rely on the AI to have copied it correctly. Pay special attention to exponents, sign conventions, and constant factors.
- Edge case handling. What happens if a user passes zero for a value that appears in a denominator? What if a negative value is passed to a function that computes a square root? AI-generated code often omits guards for these cases. Add them explicitly, or at minimum document the assumed valid input ranges.
An example of a subtle edge case failure: suppose an AI generates a function to compute the natural frequency of an undamped single-degree-of-freedom system:
import math
def natural_frequency(k, m):
return math.sqrt(k / m)
This is correct for positive k and positive m. But if m is accidentally passed as zero — perhaps because a user is building up a system incrementally and hasn't assigned the mass yet — the function raises a ZeroDivisionError with no informative message. A reviewed version would include a guard:
def natural_frequency(k, m):
if m <= 0:
raise ValueError(f"Mass must be positive, got m={m}")
if k < 0:
raise ValueError(f"Stiffness must be non-negative, got k={k}")
return math.sqrt(k / m)
Peer review — having a classmate or colleague read the code independently — is a powerful supplement to self-review. We are all prone to reading what we intended to write rather than what we actually wrote. A fresh pair of eyes catches assumptions that have become invisible to the original reviewer, notices missing units in comments, and questions design choices that seemed obvious to the author. In professional engineering, code review is a standard practice precisely because the cost of an undetected error in production is far higher than the cost of a review session.
Testing Strategies for Engineering Classes
Code review examines the code statically — by reading it. Testing examines the code dynamically — by running it against known inputs and verifying the outputs. Both are necessary. A formula can look correct on inspection and still be wrong due to a subtle operator precedence issue or an off-by-one error in an array index.
Effective testing for engineering code follows a structured approach:
- Typical inputs. Choose values that represent normal operating conditions for the engineering problem. These are the cases you care most about getting right, and they also serve as basic sanity checks.
- Boundary values. Test at the edges of the valid input domain. For a function that accepts a pipe diameter, test with very small and very large diameters. For a function that accepts a Mach number, test near zero (incompressible limit) and near one (sonic conditions).
- Known edge cases. These are inputs you already know might cause problems: zero values, negative values, very large or very small numbers that might cause floating-point overflow or underflow, inputs that make a conditional branch execute in a particular way.
- Reference values from independent sources. The strongest test cases are those whose correct answers come from a source completely independent of the code being tested — a textbook appendix, a published table, a solved example from course materials, or a result you computed by hand. If your code agrees with an independent reference on several test cases, your confidence in its correctness increases substantially.
When testing engineering code, you will almost always be working with floating-point numbers, which means exact equality comparisons are unreliable. The correct approach is to assert that the computed value is within an acceptable tolerance of the expected value. In Python, this is most cleanly done with pytest and its approx utility, or with math.isclose:
import math
def test_beam_deflection():
P = 10000 # N
L = 4.0 # m
E = 200e9 # Pa
I = 8.33e-6 # m^4
expected = (P * L**3) / (48 * E * I)
result = beam_midpoint_deflection(P, L, E, I)
assert math.isclose(result, expected, rel_tol=1e-5), (
f"Expected {expected:.6e}, got {result:.6e}"
)
The choice of tolerance matters. In most engineering calculations, a relative tolerance of 1 × 10⁻⁵ (0.001%) is appropriate for verifying formula implementation, since this is tighter than any realistic measurement uncertainty. Looser tolerances might mask errors; tighter ones might cause false failures due to floating-point arithmetic differences across platforms.
After any modification to the code — fixing a bug, adding a feature, refactoring for clarity — you should run the complete test suite again. This practice, called regression testing, ensures that a fix in one part of the code hasn't inadvertently broken another part. AI tools are particularly prone to introducing regressions when asked to modify existing code, because they regenerate the function from scratch based on your description and may silently omit a previously correct behavior.
Academic and Professional Integrity in AI-Assisted Coding
The availability of AI coding tools has created genuine ambiguity about what constitutes original work in academic and professional settings. It is important to understand both the ethical principles at stake and the practical policies that govern specific contexts.
Most universities and professional engineering organizations have either adopted explicit policies on AI use or are operating under existing academic integrity policies that apply by extension. The core question these policies address is: did the person submitting the work engage in the learning and reasoning the assignment was designed to develop? Submitting AI-generated code as your own original work, without disclosure and without genuine critical engagement, undermines this purpose — even if the code happens to be correct.
The more subtle and important point is that uncritical reliance on AI tools actively harms your own development as an engineer. Programming in engineering contexts is not primarily about producing syntactically valid code quickly. It is about translating physical understanding into computational logic, catching your own errors through disciplined testing, and building intuition about what correct results look like. These skills develop through struggle and correction. An engineer who has never independently debugged a units mismatch or tracked down a sign error in a numerical method is less capable, not more, than one who has worked through those problems — regardless of how many AI-generated functions they have used.
Disclosing AI tool use in academic and professional work is not an admission of weakness or of having taken a shortcut. It is a transparency practice with direct parallels in professional engineering. When an engineer uses commercial finite element software, they document which package and version was used, what assumptions were made, and how results were verified. The software is a tool; the engineer's judgment is what makes it legitimate. AI coding assistance fits this same model. A brief note such as "Initial code structure generated with AI assistance; all formulas verified against [reference] and tested against hand calculations for three representative cases" is an accurate and professional description of a responsible workflow.
Institutions and workplaces have varying policies, and it is your responsibility to know and follow the specific policy that applies to you. When in doubt, disclose. Transparency is always defensible; undisclosed use that later comes to light is not.
Building a Responsible AI-Assisted Workflow
The principles discussed above can be assembled into a coherent workflow that makes AI tools genuinely useful while maintaining engineering accountability. This workflow has five stages, and each stage is as important as the others.
- Plan before prompting. Before engaging an AI tool, define the engineering problem precisely. What are the inputs and their units? What are the expected outputs and their units? What formulas or methods should the solution use? What are the valid ranges of the inputs? A vague prompt produces vague code. A prompt that specifies "write a Python function that takes pipe diameter in meters, fluid velocity in m/s, fluid density in kg/m³, and dynamic viscosity in Pa·s, and returns the Darcy-Weisbach friction factor using the Moody chart approximation valid for turbulent flow with 4000 ≤ Re ≤ 10⁸" produces far more reviewable output than "write a function to calculate friction factor."
- Treat output as a draft. AI-generated code is a starting point, not a finished product. Read every line. Check variable names, units, formulas, and edge case handling as described in the code review section above. Make corrections and improvements directly — do not simply prompt the AI to fix problems, because that generates another draft requiring the same scrutiny.
- Verify numerically. Work at least two or three representative problems by hand, independent of the code. Run the code on those same inputs. Investigate any discrepancy — do not rationalize it away. A discrepancy that you cannot explain is a failure mode you have not yet found.
- Test systematically. Write test cases covering typical inputs, boundary values, and known edge cases. Assert results against independently verified reference values using appropriate floating-point tolerances. Run the test suite after every modification.
- Document everything. Record the verification steps taken: which inputs were used for hand calculations, where the reference values came from, what tests were written, and what the results were. Note that AI assistance was used and describe the nature of that assistance. This documentation serves you in three ways: it creates an audit trail if results are questioned, it forces you to be explicit about your reasoning (which surfaces gaps in understanding), and it models the professional transparency expected in engineering practice.
Throughout all of these stages, the fundamental principle is that engineering accountability cannot be delegated. An AI tool can help you write code faster, explore approaches you hadn't considered, and catch some classes of syntax errors. It cannot exercise engineering judgment on your behalf, and it cannot take responsibility for the results. Every number that flows from your code into an engineering decision — a structural analysis, a thermal calculation, a control system parameter — is ultimately your responsibility. The verification practices described here are how you honor that responsibility in an era when powerful but fallible AI tools are part of the engineering toolkit.