Δ Delta
Read Online · Part I — Foundations · Chapter 3 of 19

The Specification Frame — Your Master Key

From the free book Delta: Closing the Specification Gap (Dhuri, 2026). The PDF is the canonical edition — figures, tables, and code formatting are simplified online.

The four-element XML structure that turns statistical guessing into domain-correct output

“The Specification Frame is not a prompt template. It is a structured contract between you and the model. Fill it completely and the model has everything it needs. Leave any element empty and it fills the gap with training data averages.” — I developed the Specification Frame as an independent synthesis, refining it iteratively against the failure patterns documented in the public engineering literature and reproduced in my own experimentation. If you read only one chapter in this book, read this one. Everything else applies what is in these pages. In This Chapter

  1. The four elements: Role, Context, Task, Constraints — and why each is non-negotiable
  2. XML-tagged prompt structure and why it outperforms natural language
  3. Complete compilable Result<T> in C# (.NET 9), Java 21, and Python 3.12
  4. Complete compilable Money type in all three platforms
  5. Production system prompt templates for .NET 9, Spring Boot 3.3, Python/FastAPI, and TypeScript/Node.js
  6. Laws 3 and 4 of Enterprise AI Prompting

STOP AND THINK — Before reading on…

How do you currently structure your prompts? If a new team member used your exact approach tomorrow, would they get consistent domain-correct results — or results that depend on how well they describe the problem?

LAW 3 OF ENTERPRISE AI PROMPTING

The quality of your output is bounded by the quality of your constraint. Missing one constraint leaves one failure mode open. A .NET 9 payment service with perfect role specification, perfect context, perfect task description, and nine excellent constraints — but no idempotency constraint — will double-charge under network retry. No amount of excellence in the other elements compensates for one missing constraint. The constraint gap is exact and binary: either the constraint is specified, or the failure mode is open.

3.1 The Four Elements Element

What It Provides

Without It

XML Tag

Role

Expert identity, platform version, standing standards

Generic developer defaults. Probably not .NET 9 / Java 21 or your patterns.

<role>

Context

Interfaces, pattern examples, domain types

Model invents your <existing_interface>, architecture. Always <pattern_example>, plausibly. Always incorrectly. <domain_types>

Task

Precise specification with types and return variants

Most common output for that task category. Rarely domain-correct.

<task> Constraints

Domain rules, prohibited patterns, agent safety scope

Statistical defaults: double for money, PHI in logs, no idempotency, field injection.

20

<constraints>

3.1.1 When Constraints Conflict: Precedence You will write specifications whose constraints compete. “Return the complete implementation” pulls against “keep the response short.” “Optimize for speed” pulls against “optimize for readability.” “Handle every edge case” pulls against “ship the minimal version.” Most of the time these tensions are mild and the model resolves them sensibly. But when two constraints genuinely cannot both be fully satisfied, the model has to pick — and if you did not tell it how, it picks based on the statistical pull of its training data, not on what your domain actually needs. The result is output that violates the constraint you cared about most while faithfully honoring one you would gladly have traded away. This is a real gap in most specifications, including ones that are otherwise precise. Listing constraints tells the model what matters; it does not tell the model what matters more. The fix is one line of discipline: when constraints can conflict, state their precedence. You are not adding a new constraint — you are telling the model how to resolve the ones you already wrote when they collide. There are three good ways to express precedence, in rough order of how often you will reach for them. First, an explicit ordered rule: “If correctness and brevity conflict, prefer correctness.” Second, a non-negotiable floor: mark the constraints that may never be traded — the safety, security, and correctness invariants — as absolute, so the model knows the rest are negotiable around them. (This is what the ‘standing standard’ in your role block is reaching for; precedence makes it explicit.) Third, a tie-break of last resort: “If two constraints conflict and neither is marked absolute, prefer the one that prevents a production incident, and surface the trade-off you made.” The last clause matters as much as the rule: a model that tells you which trade-off it made hands you the decision instead of burying it. PRECEDENCE — ADD TO YOUR CONSTRAINTS BLOCK Absolute (never trade): no float for money; PHI never in logs; no SQL string interpolation. These outrank everything below.

Ordered preferences: correctness > security-hardening > completeness > brevity > performance, unless a task states otherwise. Tie-break: if two non-absolute constraints conflict, prefer the one that prevents a production incident, and state the trade-off as an ASSUMPTION line before the code. Why: a model with no precedence resolves conflicts by training-data pull, not your priorities — which is exactly how a spec that listed the right constraints still produces the wrong result.

ANTI-PATTERN — The Unranked Constraint List AVOID: a flat list of ten constraints with no indication of which is non-negotiable and which is a preference. The model cannot read your mind about which one wins, so under conflict it guesses. USE: the same ten constraints, with the two or three absolutes marked and an ordering for the rest. Same content; now the model resolves conflicts the way you would. This is the cheapest reliability gain in the whole Frame: it adds two lines and removes an entire class of confidently-wrong output.

Precedence is the part of the Constraints element that most specifications omit, and it is worth the two lines precisely because it governs the cases you did not anticipate. You cannot enumerate every conflict in advance. But you can tell the model how to choose when one arises — and a model that knows your priorities, and surfaces the trade-offs it makes, produces output you can trust under exactly the conditions where an unranked list fails you.

3.2 The Complete Specification Frame Before the template, a brief note on the choice of XML tags. The four elements could in principle be expressed in plain prose, in Markdown headings, or in JSON. XML tags are used here because they are explicitly recommended by the model providers themselves as the most reliable structural separator. Anthropic’s public prompt-engineering documentation states that XML tags “help Claude parse complex prompts unambiguously” and that the model has been trained to recognize them as a prompt-organizing mechanism (Anthropic, “Use XML tags to structure your prompts”, docs.anthropic.com/en/docs/build-with-claude/ prompt-engineering/use-xml-tags). The same recommendation appears in cloud-platform guidance: AWS’s prompt-engineering best-practices guide for Anthropic models on Amazon Bedrock notes that the model is fine-tuned to pay special attention to XML tags and recommends them for separating instructions, context, examples, and inputs (AWS Machine Learning Blog, 2024). Similar structural recognition is also reported for other frontier code-generation models: while the specific guarantees differ by provider, XML separators are widely portable across modern LLMs because their training corpora include XML and structural cues are robust to provider differences. The Specification Frame uses the same convention. The directional benefit — that prompts with explicit structural separators outperform unstructured natural-language prompts on codegeneration tasks — is also supported by published prompt-specificity research (Sajid et al., 2023, arXiv:2311.07599; see Appendix J). Sidebar: Embedding the Frame in code The Frame is XML, but it usually lives inside a string literal in your ,→ host language. Different languages have different ways of

,→ carrying multi-line content with angle brackets. Use the right ,→ one and the prompt stays readable; use the wrong one and you ,→ spend an afternoon fighting backslashes. C# 13: use raw string literals """..."""

(C# 11+) — no escaping

,→ required for <, >, or quotes inside. Verbatim strings (@"...") ,→ work too but require doubled quotes. Java 21:

use text blocks """..."""

(Java 15+, standard from 17) —

,→ multi-line, indentation-aware, no escaping for angle brackets. ,→ Always close the """ on its own line for predictable indent ,→ stripping. Python 3.12: ,→ use triple-quoted strings """..."""

— or r"""...""" if your prompt contains backslashes you do not want interpreted.

,→ textwrap.dedent() removes common indentation. TypeScript: use template literals `...`

— multi-line, supports ${
,→ interpolation}. Watch for accidental ${} inside your prompt ,→ content; escape with \${ if literal. The recommended pattern: ,→ keep prompts in separate .md or .txt files (see Chapter 11) and ,→

load them rather than embedding in code at all. <!-- The SPECIFICATION FRAME — All Four Elements, XML-Tagged --> <role> You are a [seniority] [language] engineer on a [domain] platform. Stack: [technology with exact versions]. [One standing standard that applies to all code in this context.] </role> <architecture> [Pattern: Clean Architecture / DDD / Layered / Hexagonal] [Error handling: Result<T> for business rules, exceptions for ,→ infrastructure] [DI style: constructor injection / @RequiredArgsConstructor] [Event pattern: publish after commit / never inside @Transactional] </architecture> <existing_interface> [The exact interface the generated code must implement.] [Always include for implementation tasks. The model ’cant infer it ,→ .] </existing_interface> <pattern_example> [One existing implementation from your codebase: –2040 lines of ,→ method body.] [This shows your naming, structure, and style better than any ,→ description.] [Do NOT paste the full class. Let MCP read the file for full-file ,→ tasks.] </pattern_example> <domain_types> [Non-obvious types the code will use: Money<T>, Result<T>, custom ,→ value objects.] [If these are in Appendix B: paste them. The model ’cant infer ,→ proprietary types.] </domain_types> <task> Implement [ClassName.MethodName] that: - [Concrete requirement 1 with specific input types and expected ,→ return values] - [Concrete requirement 2] - Returns [specific return type, ALL variants: success and each ,→ failure case] </task> <constraints> - [Domain correctness: Money<T> not decimal; PHI not in logs] - [Architectural: IRequest<Result<T>> for commands; ,→ @RequiredArgsConstructor] - [Prohibition: Never use double for money; never @Autowired fields ,→ ] - [Agent safety: Do not modify .csproj / pom.xml without ,→ instruction] Include ALL using directives (C#) / package and all imports (Java). Compilable code only. No pseudocode. No TODO: implement. </constraints>

LAW 4 OF ENTERPRISE AI PROMPTING

Context not provided is context invented. The model fills every gap — just not with your actual codebase. When you omit your error handling pattern, the model picks the most common one — which is throwing exceptions where you return Result<T>. When you omit your Money type, it uses decimal or double. When you omit your DI style, it uses @Autowired field injection. All of these inventions are plausible. None matches what your code reviewers expect. Every blank is an invention. Every invention might not be correct.

3.3 Result<T> — Complete Compilable Implementation This is the Result<T> type used in every code example in this book. Add it to your shared library before using any Part II recipe. It is also in Appendix B with the Java version.
C# — Result<T> (.NET 9) — src/Common/Result.cs namespace YourCompany.Common; /// <summary> /// Discriminated union: success value or structured failure. /// Use for all business rule outcomes. Never throw for business rule ,→

failures.

/// </summary> public sealed class Result<T> { public bool IsSuccess { get; } public T? Value { get; } public string? ErrorCode { get; } public string? ErrorMessage { get; } private Result(bool ok, T? value, string? code, string? msg) => (IsSuccess, Value, ErrorCode, ErrorMessage) = (ok, value, ,→ code, msg); public static Result<T> Success(T value) => new(true, value, null, null); public static Result<T> Failure(string errorCode, string ,→ errorMessage) => new(false, default, errorCode, errorMessage); public Result<TOut> Map<TOut>(Func<T, TOut> mapper) => IsSuccess ? Result<TOut>.Success(mapper(Value!)) : Result<TOut>.Failure(ErrorCode!, ErrorMessage!); public T GetValueOrThrow() => IsSuccess ? Value! : throw new InvalidOperationException($"[{ErrorCode}] { ,→ ErrorMessage}"); // Void result for commands that produce no value public static readonly Result<Unit> VoidSuccess = new(true, Unit. ,→ Value, null, null); } public sealed class Result { public bool IsSuccess { get; } public string? ErrorCode { get; } public string? ErrorMessage { get; } private Result(bool ok, string? c, string? m) => (IsSuccess, ,→ ErrorCode, ErrorMessage) = (ok, c, m); public static Result Success() => new(true, null, null); public static Result Failure(string code, string msg) => new( ,→ false, code, msg); } public readonly struct Unit { public static readonly Unit Value = default; } Java 21 — Result<T> — src/main/java/com/yourcompany/common/Result. ,→ java package com.yourcompany.common; import java.util.Objects; import java.util.Optional; import java.util.function.Function; /** * Discriminated union: success value or structured failure. * Use for all business rule outcomes. Never throw checked exceptions ,→ for business rules.

*/ public final class Result<T> { private final boolean success; private final T value; private final String errorCode; private final String errorMessage; private Result(boolean success, T value, String errorCode, String ,→

errorMessage) { this.success = success; this.value = value; this.errorCode = errorCode; this.errorMessage = errorMessage; } public static <T> Result<T> success(T value) { Objects.requireNonNull(value, "Success value must not be null ,→ "); return new Result<>(true, value, null, null); } public static <T> Result<T> failure(String errorCode, String ,→ errorMessage) { Objects.requireNonNull(errorCode, "Error code required"); return new Result<>(false, null, errorCode, errorMessage); } public boolean isSuccess()

{ return success; }
public Optional<T> getValue()
{ return Optional.ofNullable
,→ (value); } public String getErrorCode()
{ return errorCode; }
public String getErrorMessage()
{ return errorMessage; }

public <R> Result<R> map(Function<T, R> mapper) { return success ? Result.success(mapper.apply(value)) : Result.failure(errorCode, errorMessage); } public T getValueOrThrow() { if (!success) throw new IllegalStateException( "[" + errorCode + "] " + errorMessage); return value; } } 3.4 Money<T> — Complete Compilable Implementation The Obsolete attribute on the double constructor in the C# version is not a style choice. It turns the most common AI mistake into a compile-time error. The first time your CI pipeline rejects ’new Money<USD>(0.1)’ from an AI-generated service, you will understand why it is there. C# — Money<T> (.NET 9) — src/Domain/ValueObjects/Money.cs namespace YourCompany.Domain.ValueObjects; // Currency marker structs — add yours here public readonly struct GBP; public readonly struct USD; public readonly struct EUR; /// <summary> /// Immutable monetary value with currency type parameter. /// The Obsolete(error:true) constructor prevents AI-generated double ,→ usage at compile time.

/// </summary> public sealed record Money<TCurrency>(decimal Amount, int Scale = 2) where TCurrency : struct { // This constructor is a COMPILE ERROR — prevents the most common ,→

AI mistake:

[Obsolete("Never construct Money from double — use decimal ,→ literal", error: true)] public Money(double amount) : this((decimal)amount) { } public Money<TCurrency> Add(Money<TCurrency> other) => this with { Amount = Amount + other.Amount }; public Money<TCurrency> Subtract(Money<TCurrency> other) => this with { Amount = Amount - other.Amount }; public Money<TCurrency> Multiply( decimal factor, MidpointRounding mode = MidpointRounding.AwayFromZero) => this with { Amount = Math.Round(Amount * factor, 4, mode) }; /// <summary>Rounds to Scale decimal places for storage or output ,→ .</summary> public Money<TCurrency> Round( MidpointRounding mode = MidpointRounding.AwayFromZero) => this with { Amount = Math.Round(Amount, Scale, mode) }; public bool IsPositive

=> Amount > 0m;
public bool IsZero
=> Amount == 0m;
public bool IsNegative
=> Amount < 0m;

public static Money<TCurrency> Zero => new(0m); } Java 21 — Money — src/main/java/com/yourcompany/domain/Money.java package com.yourcompany.domain; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Currency; import java.util.Objects; /** * Immutable monetary value. Factory methods enforce BigDecimal ,→ precision. * double and float are not accepted — pass String or BigDecimal to ,→ Money.of(). */ public record Money(BigDecimal amount, Currency currency) { public Money { Objects.requireNonNull(amount,

"Amount required");

Objects.requireNonNull(currency, "Currency required"); } /** Factory: use this for all construction. String avoids float ,→ precision loss. */ public static Money of(String amount, String currencyCode) { return new Money( new BigDecimal(amount).setScale(4, RoundingMode.HALF_UP), Currency.getInstance(currencyCode)); } public static Money of(BigDecimal amount, Currency currency) { return new Money(amount.setScale(4, RoundingMode.HALF_UP), ,→ currency); } public Money add(Money other)

{ assertSameCurrency(other);

,→ return new Money(amount.add(other.amount), currency); } public Money subtract(Money other) { assertSameCurrency(other); ,→ return new Money(amount.subtract(other.amount), currency); } public Money multiply(BigDecimal factor) { return new Money(amount.multiply(factor).setScale(4, ,→ RoundingMode.HALF_UP), currency); } /** Use forOutput() for display, API responses, and persistence. ,→ */ public BigDecimal forOutput() { return amount.setScale(2, ,→ RoundingMode.HALF_UP); } private void assertSameCurrency(Money other) { if (!currency.equals(other.currency)) throw new ArithmeticException( "Currency mismatch: " + currency + " vs " + other. ,→ currency); } public static final Currency GBP = Currency.getInstance("GBP"); public static final Currency USD = Currency.getInstance("USD"); public static final Currency EUR = Currency.getInstance("EUR"); }

QUICK WIN — 25 minutes

Copy both Result<T> implementations into your shared library right now. Then check your last three AI-generated services: do they use Result<T> for business outcomes? If not, update the re- turn types. This single exercise makes all subsequent AI generation consistent with your error handling standard.

3.5 Production System Prompt Templates The system prompt is the highest-ROI document in your AI workflow. It runs before every request. Write it once, cache it, evolve it quarterly. Here are production-ready starting templates for both platforms: .NET 9 Team System Prompt (claude.ai Project settings) <s> <identity> Senior C# engineer at [Company] on our [domain] platform. Stack: .NET 9 / C# 13 / EF Core 9 / MediatR 12 / Npgsql (PostgreSQL) ,→ </identity> <architecture> Pattern: Clean Architecture (Domain / Application / Infrastructure / ,→

Presentation)

CQRS:

MediatR 12 — commands: IRequest<Result<T>>, queries:
,→ IRequest<TResponse> DI:

Constructor injection only — never property or field

,→ injection ORM:

EF Core 9 Code-First — Npgsql PostgreSQL 16

Validation: FluentValidation 11 with AbstractValidator<T> Testing: xUnit 2 + NSubstitute 5 + FluentAssertions 6 + coverlet Logging: Serilog structured parameters ONLY — never string ,→ interpolation in log calls Errors:
Result<T> for business rules, exceptions for
,→ infrastructure failures only </architecture> <domain_rules> [REPLACE with your ’teams domain rules — examples below:] Money<TCurrency> for ALL monetary values — never decimal directly. All POST endpoints: idempotent via X-Idempotency-Key header.

Domain events: IDomainEventDispatcher.DispatchAsync() AFTER ,→ SaveChangesAsync(). PHI (patient name, DOB, diagnosis, medication): NEVER in log ,→ statements. </domain_rules> <output_rules> Include ALL using directives. Include namespace. No pseudocode. Complete compilable code. TODO only for team-specific integration ,→ points. Sealed on all concrete classes unless inheritance is required. UNIVERSAL OUTPUT RULES (apply to every generation request): - ONE implementation. No alternatives. No 'you could also...' ,→ sections. - If ambiguous: ASSUMPTION: [what] because [why] BEFORE the code. - NEVER X without ALWAYS Y: for each prohibition, specify the ,→ alternative. </output_rules> </s> Java 21 / Spring Boot 3.3 Team System Prompt <s> <identity> Senior Java engineer at [Company] on our [domain] platform. Stack: Java 21 LTS / Spring Boot 3.3 / Spring Data JPA / Hibernate ,→ 6 / PostgreSQL 16 </identity> <architecture> Pattern:

Layered (Controller / Service / Repository / Domain)

DI:

Constructor injection ONLY — @RequiredArgsConstructor (
,→ Lombok). NO @Autowired. ORM:
Spring Data JPA / Hibernate 6. @Version on all @Entity
,→ for optimistic locking. Validation: Jakarta Validation 3 (Bean Validation). @Valid on ,→ controller params. Testing: ,→
JUnit 5 + @ExtendWith(MockitoExtension.class) + AssertJ

+ Spring test slices.

Logging:

33

SLF4J @Slf4j — {} placeholders ONLY. Never String.

,→ format() in log calls. Errors:

Result<T> from service layer. Unchecked exceptions for

,→ infrastructure only. </architecture> <domain_rules> [REPLACE with your ’teams domain rules — examples below:] Money value object for all monetary amounts — never double, float, ,→ or raw BigDecimal. All @Entity: UUID PK with @UuidGenerator, @Version field for ,→ optimistic locking. Events: ApplicationEventPublisher, published AFTER transaction ,→ commit. @AuditLog annotation on all methods accessing PHI (healthcare ,→ projects). </domain_rules> <output_rules> Include package declaration and ALL imports. No pseudocode. ,→ Compilable code. TODO only for team-specific integration points that require local ,→ knowledge. </output_rules> </s> Python 3.12 / FastAPI / Pydantic System Prompt <s> <identity> Senior Python engineer at [Company] on our [domain] platform. Stack: Python 3.12 / FastAPI 0.115 / Pydantic v2 / SQLAlchemy 2 / ,→ PostgreSQL 16 </identity> <architecture> Pattern:

Layered (Router / Service / Repository / Domain models)

DI:

FastAPI Depends() for all dependency injection

Validation: Pydantic v2 BaseModel with strict mode for ALL inputs ORM:

34

SQLAlchemy 2 async (AsyncSession). Alembic for

,→ migrations. Testing: pytest + pytest-asyncio + httpx AsyncClient

Logging: structlog — bound context keys. Never f-string log

,→ messages. Errors: ,→

Result pattern via returns library or explicit Union[T,

Error] types.

</architecture> <domain_rules> [REPLACE with your ’teams domain rules — examples below:] Decimal for ALL monetary amounts — never float or int cents directly ,→ . Pydantic model with @validator for all money fields: Decimal with ,→ scale=2. PHI (patient name, DOB, diagnosis): NEVER in log messages. All async endpoints: async def. Never mix sync and async in same ,→ service. </domain_rules> <output_rules> Include all imports. Pydantic models first, then service, then ,→ router. Type-annotated throughout — no implicit Any. ONE implementation. No alternatives. No ‘you could …’also sections. If ambiguous: ASSUMPTION: [what] because [why] BEFORE the code. </output_rules> </s> TypeScript / Node.js / NestJS System Prompt <s> <identity> Senior TypeScript engineer at [Company] on our [domain] platform. Stack: Node.js 22 LTS / NestJS 10 / TypeORM 0.3 / PostgreSQL 16 / ,→ Zod 3 </identity> <architecture> Pattern:

NestJS modules (Controller / Service / Repository /

,→ Entity) DI:

NestJS @Injectable() constructor injection ONLY.

Validation: Zod schemas for ALL external inputs. class-validator in ,→

DTOs.

ORM:

TypeORM with DataSource. Migrations: TypeORM migration

,→ files. Testing:

Jest + @nestjs/testing. Unit: isolated with jest.mock().

,→ Logging: ,→

Pino structured logger. Never console.log in production

code.

Errors:

Result<T, E> type OR typed exceptions extending
,→ HttpException. </architecture> <domain_rules> [REPLACE with your ’teams domain rules — examples below:] Decimal.js or string representation for ALL money — never JS number ,→

for currency.

Zod: .strict() on all external schemas — strip unknown fields at ,→ boundary. async/await throughout. No raw Promises. No .then() chains. All controllers: @UseGuards(JwtAuthGuard) unless explicitly public. </domain_rules> <output_rules> Include all imports. TypeScript strict mode compatible. ONE implementation. No alternatives. If ambiguous: ASSUMPTION ,→ before code. </output_rules> </s>

“Teams that invest forty minutes writing a shared system prompt routinely report several sprints of AI-assisted PRs without a single ‘wrong pattern’ review comment, against a baseline of one or two pattern corrections per PR. The system prompt is consistently described as the highest-ROI engineering investment in this category.” — Engineering Manager, UK FinTech, FCA-regulated

Key takeaways

Constraints in XML tags. Every empty element is filled with training data averages. Averages are wrong for your domain. + Result<T> and Money<T> are fully implemented in this chapter and Appendix B. Add them to your shared library before using any Part II recipe. + The system prompt is the highest-ROI document in your AI workflow. One hour writing it saves one correction per PR, every PR, indefinitely. + Laws 3 and 4: output quality is bounded by constraint quality; context not provided is context invented. Every blank specification element is a failure mode waiting to happen. + Five constraint categories: domain correctness, architectural fit, anti-pattern prohibition, style consistency, and agent safety scope. A prompt with entries in all five has no Specification Gaps.

TRY IT NOW

  1. Copy both Result<T> and Money<T> implementations into your shared library. Verify they compile cleanly in your project.
  2. Write your team’s system prompt using the templates from Section 3.5. Include at least three domain-specific rules in <domain_ rules>. Deploy it this week.
  3. Take the last complex prompt you wrote and restructure it using all six XML tags. Compare the output to the original. Write down which domain constraints the structured version produces that the unstructured one missed.
UP NEXT — Chapter 4: Code Generation — Ten Production Recipes

The Frame is the structure. Chapter 4 is the payload: ten production recipes — payments, PHI-safe logging, idempotent webhooks, optimistic locking — each one a complete Specification Frame you can adapt to your domain this week. PART II CORE PATTERNS Chapters –49

Six patterns. Every recipe grounded in compilable code. Every failure mode documented. Part II is the practical engine of the book. Six chapters cover code generation, code review, debugging, documentation, architecture, and testing — the six activities where AI assistance delivers the most immediate, measurable ROI. The examples were developed against current .NET 9 and Java 21 toolchains and align with the idiomatic patterns in the official Microsoft and Spring documentation; the foundational implementations ship with runnable test suites in the companion repository. Every chapter has at least two Before/After comparisons.

Cite this chapter
Dhuri, Sandeep. (2026). Delta: Closing the Specification Gap. Acuity Press. Chapter 3.
DOI