Embed Business Logic: Architect Software AI Can Actually Learn
Most software organizations do not lack code. They lack the context that explains why the code exists, which rules are non-negotiable, and what must happen when reality gets messy. That distinction matters enormously when introducing AI into a product or engineering workflow.
An AI system can generate functions, call tools, summarize tickets, and propose changes. But unless business logic is made explicit and reachable, it is learning from the least reliable artifact available: scattered implementation details. The result may look competent in a demo while quietly violating the rules that make the business work.
The practical goal is not to “teach the model everything.” It is to architect software so important decisions are expressed in forms that both people and AI systems can find, interpret, test, and safely use.
Business logic is more than code paths
Business logic includes the policies and constraints that determine what the system is allowed to do. A shipping rule, approval threshold, pricing exception, entitlement check, retention policy, or refund workflow is business logic even when it is currently hidden inside a controller, a database trigger, a spreadsheet, or somebody’s memory.
AI struggles when these rules are implicit. Consider an agent asked to add a “cancel subscription” action. It may find the table schema and the billing API integration, then produce code that marks a subscription as cancelled. Yet the real process may require preserving access through the paid period, blocking cancellation during a dispute, notifying an account owner, and recording a compliance event.
None of those requirements are obvious from a column named status.
Make decisions legible and local
The first architectural move is to put decisions where they can be understood. This does not require a grand rules engine for every application. It does require resisting the habit of distributing one policy across UI conditions, API handlers, background jobs, and ad hoc queries.
A useful pattern is to give a named domain operation responsibility for a business decision. Instead of allowing many callers to mutate a record directly, provide an operation that accepts the relevant facts and returns an explicit result.
type CancellationDecision =
| { allowed: true; accessEndsAt: Date }
| { allowed: false; reason: "active_dispute" | "missing_permission" };
function decideCancellation(input: {
hasPermission: boolean;
hasActiveDispute: boolean;
paidThrough: Date;
}): CancellationDecision {
if (!input.hasPermission) {
return { allowed: false, reason: "missing_permission" };
}
if (input.hasActiveDispute) {
return { allowed: false, reason: "active_dispute" };
}
return { allowed: true, accessEndsAt: input.paidThrough };
}
This is not merely cleaner code. It creates a stable unit of meaning. A developer can review it, a test can exercise it, documentation can point to it, and an AI coding assistant can use it instead of reconstructing policy from fragments.
Separate policy, orchestration, and side effects
AI-assisted development becomes much safer when the system distinguishes three concerns:
- Policy: what is permitted, required, or prohibited.
- Orchestration: the ordered workflow that applies a decision.
- Side effects: database writes, emails, payments, messages, and external API calls.
In the subscription example, the cancellation decision is policy. Updating the subscription, scheduling access expiry, recording an audit event, and notifying billing are orchestration and side effects. Mixing all of that into one large endpoint makes it difficult for a person or model to identify what must remain true.
This separation also gives agents safer boundaries. An agent may be allowed to draft a policy test or propose an orchestration change, while production side effects stay behind reviewed interfaces. The more consequential an action is, the less acceptable it is to infer its meaning from natural-language prompts alone.
Turn rules into executable examples
Documentation helps, but prose is ambiguous by nature. Tests convert critical expectations into something the system can verify. For AI work, tests are also a feedback mechanism: they show the assistant which behavior matters and catch plausible but incorrect modifications.
Favor examples that describe a meaningful scenario, not only implementation details.
it("keeps access active until the paid-through date", () => {
const decision = decideCancellation({
hasPermission: true,
hasActiveDispute: false,
paidThrough: new Date("2030-06-30T00:00:00Z")
});
expect(decision).toEqual({
allowed: true,
accessEndsAt: new Date("2030-06-30T00:00:00Z")
});
});
Boundary cases deserve special attention: time zones, retries, duplicate events, missing data, permission changes, partial failures, and conflicting updates. These are exactly the areas where a code-generating model may produce something that looks reasonable but breaks operational reality.
Give agents tools, not broad authority
Embedding business logic does not mean placing every rule in a prompt. It means exposing carefully designed capabilities. An agent that needs to answer whether an order can be returned should call a return-eligibility operation rather than inspect raw order records and improvise an answer.
Good tool boundaries make inputs, outputs, permissions, and failure states explicit. A tool that performs a consequential action should make a dry-run or validation path available where practical. For example, previewRefund can explain eligibility and the expected amount before a separately authorized issueRefund action runs.
Idempotency matters as well. Agents retry. Networks fail. Background workers repeat messages. If an operation can cause a charge, notification, or record transition, its interface should state how duplicate requests are handled. Reliable automation depends less on a model’s confidence than on the system’s behavior when that confidence is wrong.
Build a shared map of the domain
Names are part of the architecture. If one service calls something a “customer,” another calls it an “account,” and a third calls it an “organization,” both humans and AI will make incorrect joins between concepts. Establish a small domain vocabulary and use it in code, APIs, tests, and documentation.
Keep concise explanations close to the code for rules that are easy to misunderstand. Link a policy to its tests and to the workflow that enforces it. The aim is not exhaustive documentation; it is reducing the number of places where someone must guess.
Make AI a participant in a well-designed system
The strongest AI strategy is not to ask a model to compensate for unclear software. It is to improve the software until important knowledge has a home: named operations for decisions, tests for examples, tools for actions, and audit trails for consequences.
When business logic is embedded this way, AI becomes more useful because it has better rails to follow. Developers gain the same benefit. The architecture that helps a model learn your system is usually the architecture that helps your team change it without losing the reasons it was built.