Contents
  1. Purpose and development
    1. Engineering around learned behavior
    2. Must-know turning points
  2. Interfaces and obligations
    1. Specify what an operation promises
      1. One interface, several obligations
    2. Validate external values
      1. Structure and meaning are different checks
  3. Boundaries, state and effects
    1. Hide decisions behind useful boundaries
      1. Replaceable dependencies
      2. Decisions and effects
    2. Preserve state at acceptance
      1. Optimistic acceptance
    3. Represent uncertain external outcomes
      1. Safe repetition requires a contract
  4. Testing the right claims
    1. Match checks to claims
    2. Control dependencies in focused tests
      1. Test observable obligations
      2. Vary inputs, keep the oracle explicit
    3. Exercise real integration boundaries
      1. Check both sides of an interaction
  5. Reproduction and diagnosis
    1. Replay the failed boundary
      1. Execution context for replay
    2. Test explanations of a failure
      1. A discriminating experiment
      2. Reduce without changing the failure
  6. Controlled change
    1. Make changes reviewable
    2. Identify what was tested and released
  7. Exposure and recovery
    1. Limit exposure and stop new work
    2. Restore software without erasing effects
      1. Recovery has separate responsibilities
  8. Check understanding
  9. Open questions
  10. Selected talks
  11. References
  12. Talk library
← All topics

Software Engineering Fundamentals

A model can produce a plausible answer without producing the right answer. Software engineering cannot remove that uncertainty, but it can determine which values the application will accept, which state changes are legal, which effects may occur, how failures are reproduced, and what evidence must accompany a release. The central discipline is to separate a model’s proposal from the software’s obligations. That separation lets engineers make strong, limited claims about application behavior without confusing a valid interface, a repeatable output, or a passing test with useful model performance.

Purpose and development

Engineering around learned behavior

Traditional application code contains rules written directly by programmers. A machine-learning model instead derives some behavior from training data: it predicts or generates an output from patterns learned during training. Machine Learning Fundamentals develops that mechanism; here, the important consequence is that a permitted input can still receive an incorrect output.

That uncertainty does not make ordinary engineering irrelevant. The model may propose a category, message, or action, while application code decides whether the proposal is well formed, whether the caller is authorized, whether current state still permits it, and whether an external effect should occur. Code can enforce those responsibilities even though it cannot guarantee that every prediction is useful. Essential control flow, tool definitions, and information-flow restrictions therefore belong in explicit software rather than being left for a model to infer on each request.

Repeatability and correctness are separate properties. Repeating the same answer only shows stability under the tested conditions; correctness asks whether the answer satisfies the intended requirement. Model-containing systems also have dependencies that cross clean-looking code boundaries: data, configuration, feedback loops, and downstream consumers can make a model change affect behavior beyond its adapter. The practical goal is therefore not to pretend that uncertainty disappeared. It is to state each software guarantee precisely and collect separate empirical evidence for model behavior.

Must-know turning points

Several complementary lines of work shaped this approach. The dates below identify the cited publications or announcements, not universal invention dates, and their sequence does not imply that later practices replaced earlier ones.

These landmarks connect explicit obligations, information hiding, integrated checks, learned-system dependencies, and checked model interfaces.
DateLandmarkContribution
October 1969An Axiomatic Basis for Computer Programming, C. A. R. HoareConnected assumptions about an initial state to properties established when a program terminates, including rules for composing program parts.
December 1972On the Criteria To Be Used in Decomposing Systems into Modules, David ParnasOrganized modules around design decisions they conceal, so callers need not change when a hidden representation changes.
September 2000Continuous Integration, Martin Fowler and Matthew FoemmelDocumented frequent integration with an automated build and test process, intended to expose interactions while changes remained small and recent.
2015Hidden Technical Debt in Machine Learning Systems, D. Sculley and colleaguesExplained how data, configuration, feedback, and consumers can couple learned components beyond apparent code boundaries.
July 2023Introducing TypeChat, MicrosoftApplied TypeScript definitions and compiler diagnostics to checking model-generated records before application use.

Interfaces and obligations

Specify what an operation promises

A type describes permitted values and operations. An interface exposes how another component can interact with a module. A type named SanitizedString, for example, is still an ordinary string unless some operation actually checks or constructs the promised property.

A precondition is an obligation placed on the caller before an operation begins. A postcondition is an obligation the implementation owes after successful completion. If one operation’s postcondition establishes the next operation’s precondition, the two can be composed without every caller knowing their internals. Hoare’s 1969 rules supplied a formal foundation for this reasoning; Bertrand Meyer’s Applying Design by Contract, published in October 1992, presented contracts as practical guidance for reusable components. These ideas do not require turning an application into a formal proof.

One interface, several obligations

Consider acceptLabel(recordId, expectedVersion, label). Its useful contract extends beyond the parameter types.
ElementOwnerObligation
Input valuesCallerSupply an existing record identifier, the version used to produce the proposal, and a label from the declared set.
Acceptance conditionImplementationAccept only if the authoritative record still has expectedVersion and the requested transition is allowed.
Successful resultImplementationStore the label and advance the record version together.
Rejected resultInterfaceReturn an explicit reason such as invalid label, stale version, or unavailable storage.

Static checking can reject incompatible program expressions before execution, but it cannot inspect a value that has not arrived yet. TypeScript, for example, erases ordinary type annotations when producing JavaScript. Runtime values from a model, HTTP request, database, or file therefore need runtime checks. Declared failures are also not automatically contract violations: an unavailable dependency can be an expected outcome represented by the interface, while silently returning malformed success violates the operation’s promise.

Validate external values

External bytes pass through several distinct questions. Parsing asks whether bytes can be interpreted as a value. Schema validation asks whether that value has the declared fields, types, required properties, and allowed values. Application rules ask whether the value is permitted in the current domain and state. Prediction assessment asks whether the model interpreted the input correctly. Each layer can reject a value, but passing one layer does not imply passing the next.

Each boundary establishes a narrower guarantee

Parsing, schema validation, domain acceptance, persistence, and task evaluation support different claims.

Parsing does not establish schema conformance; schema conformance does not establish domain permission or semantic correctness. Accepted persistence requires a valid state transition, while task evaluation supplies separate evidence about model usefulness.
Read the diagram as text
  • External bytes. A model or another external source supplies untrusted input.
  • Parse. Interpret the bytes as a value or return a parsing failure.
  • Validate schema. Check required fields, types, and allowed values; preserve explicit failure outcomes.
  • Validated proposal. The record satisfies the checked runtime shape, but its meaning is not yet established.
  • Apply domain and state rules. Check authorization, permitted transitions, and current authoritative state.
  • Persist atomically. Commit the accepted mutation while preserving its state-transition contract.
  • Authoritative accepted state. Software has established the promised state change, not the model’s general usefulness.
  • Parsing failure. The bytes cannot be interpreted as the expected value.
  • Invalid or unavailable result. Malformed output or an explicit dependency failure is not treated as successful data.
  • Rejected operation. The proposal is disallowed, unauthorized, or stale for the current state.
  • Representative labeled cases. Examples and conditions selected for the intended task.
  • Task-specific oracle. Metrics or review criteria judge whether interpretations satisfy the task.
  • Task-quality evidence. Observed evaluation results support bounded claims about model usefulness.
  • External bytesParse: interpret.
  • ParseValidate schema: parsed value.
  • ParseParsing failure: reported failure.
  • Validate schemaValidated proposal: validated record.
  • Validate schemaInvalid or unavailable result: explicit rejection.
  • Validated proposalApply domain and state rules: candidate data.
  • Apply domain and state rulesPersist atomically: accepted transition.
  • Apply domain and state rulesRejected operation: explicit rejection.
  • Persist atomicallyAuthoritative accepted state: committed state.
  • Validated proposalTask-specific oracle: evaluated output.
  • Representative labeled casesTask-specific oracle: task conditions.
  • Task-specific oracleTask-quality evidence: assessment results.

Structure and meaning are different checks

Suppose the allowed sentiment labels are positive, neutral, and negative, and the input is “The battery failed after one day.”
Returned valueParses?Matches schema?Interpretation
{"label": 7}YesNoThe label is not one of the permitted strings.
{"label": "positive"}YesYesStructurally acceptable, but inconsistent with the unambiguous complaint.
{"label": "negative"}YesYesStructurally acceptable and consistent with this input.
{"status": "unavailable", "reason": "provider_timeout"}YesSeparate failure schemaNo successful classification is claimed.

The second record is the crucial case: a validator can establish that positive is allowed without establishing that it describes the input. Conversely, a provider timeout should not be converted into neutral, an empty label, or another fabricated success. The interface should preserve unavailable or rejected outcomes so downstream code cannot mistake absence of a prediction for a prediction about absence.

Microsoft’s TypeChat used the same TypeScript definitions to guide generated data and check it, feeding compiler diagnostics into a repair request when validation failed. That is a concrete boundary mechanism, not a guarantee that the model understood the request. Daniel Rosenwasser’s TypeChat talk demonstrates the approach. Structured Outputs and Tool Calling develops constrained generation, argument validation, and action handling in depth.

Boundaries, state and effects

Hide decisions behind useful boundaries

A module is a unit with a focused responsibility and an explicit interface. Information hiding places a changeable decision inside the module that owns it, so callers depend on the stable interface rather than the hidden representation. Cohesion groups logically related responsibility; limited coupling keeps one component from needing to know another component’s internal decisions.

In a model-based application, provider wire formats, application acceptance policy, and persistence often change for different reasons. A model adapter can translate provider responses into an internal result. Domain rules can decide whether that result is allowed. A storage adapter can make the accepted state transition. If a provider changes only its response envelope, the model adapter may contain the change. If the replacement model changes classification behavior, the internal interface may remain identical while broader evaluation is still necessary.

Boundaries contain knowledge, not all consequences

A provider-format change can remain inside the model adapter, while a behavior change can cross the same stable interface and still require broader evaluation.

The coordinator depends on domain rules and internal adapter interfaces. Provider wire-format knowledge belongs in the model adapter; persistence details belong in the storage adapter. Arrows show code dependencies, not runtime order or proof that model replacements are behaviorally equivalent.
Read the diagram as text
  • Application coordinator. Sequences acceptance without owning provider or storage formats.
  • Domain rules. Own permitted transitions and acceptance policy.
  • Model adapter. Translates provider requests and responses into the internal result contract.
  • Model provider. External inference service with its own wire format and behavior.
  • Storage adapter. Owns persistence operations and database-specific behavior.
  • Authoritative database. Stores accepted application state.
  • Application coordinatorDomain rules: code: acceptance policy.
  • Application coordinatorModel adapter: code: internal result contract.
  • Application coordinatorStorage adapter: code: state interface.
  • Model adapterModel provider: data: provider wire format.
  • Storage adapterAuthoritative database: data: persistence protocol.

Replaceable dependencies

Dependency injection means supplying a dependency to a consumer instead of constructing it inside the consumer. It creates an explicit replacement point for a real provider, a controlled test double, or another implementation; no framework or separate service is required. Large dependency graphs can nevertheless become hard to trace, so the provisioning path should remain visible. Matt Pocock’s software-fundamentals talk relates this to deep modules: substantial responsibility behind a simple interface. Depth is a relationship between functionality and interface complexity, not a target file size.

Decisions and effects

A pure function returns the same result for the same inputs and does not modify pre-existing external state. Gary Bernhardt’s July 2012 functional core, imperative shell pattern places value transformations and decisions in a testable core while a surrounding shell performs database, network, and terminal effects. This separation is useful when it clarifies ownership; adding shallow wrappers that merely forward calls creates navigation cost without hiding a meaningful decision.

Preserve state at acceptance

State is information retained between operations. A state transition changes that information. An invariant is a condition that must hold at the boundaries where the system claims to be in a valid state. An invariant may be temporarily false during an internal calculation, but every exported successful operation must re-establish it before making the new state visible.

Suppose a model proposes a label using record version 12. While inference runs, another operation changes the record and advances it to version 13. The proposal can remain well formed yet no longer be eligible for acceptance. Reading version 13 in a separate preflight check is insufficient if another writer can update the record between that check and the eventual write.

Optimistic acceptance

An atomic conditional update compares the expected version and performs the mutation as one database operation. PostgreSQL’s Read Committed behavior rechecks an UPDATE condition against a row changed by another transaction. The application can therefore update only where id and version = 12, increment the version in the same statement, and treat zero affected rows as stale-proposal rejection. Every relevant writer must participate by advancing the version. This single-row pattern does not establish arbitrary multi-row invariants.

Check and write must share one database operation

Example

A preflight read can become stale before a later write; a conditional update rejects the proposal when its expected version no longer matches.

1 / 6 · Proposal targets version 12

Both paths begin with proposal P tied to record version 12.

Proposal P was computed from version 12. In the unsafe path, a concurrent writer advances the row after the preflight read. In the safe path, one conditional update matches the record and version, stores the label, and advances the version together; zero affected rows means stale rejection.
Read the diagram as text
  • Proposal P · version 12. A label proposal bound to the state used during inference.
  • Preflight reads version 12. The application observes a matching version before issuing a separate write.
  • Concurrent writer creates version 13. Another accepted mutation advances the authoritative row.
  • Later unconditional write. The separated write can apply P after its source version has become stale.
  • Conditional UPDATE. Match record id and version 12; store the label and increment the version in the same operation.
  • Database rechecks version 13. The authoritative row no longer satisfies the version-12 predicate.
  • Zero rows affected. No state mutation occurs because the expected version does not match.
  • Reject as stale. The application reports that P is no longer eligible for acceptance.
  • Proposal P · version 12Preflight reads version 12: separate freshness check.
  • Preflight reads version 12Concurrent writer creates version 13: intervening state change.
  • Concurrent writer creates version 13Later unconditional write: stale write remains possible.
  • Proposal P · version 12Conditional UPDATE: expected version supplied.
  • Conditional UPDATEDatabase rechecks version 13: database evaluates predicate.
  • Database rechecks version 13Zero rows affected: version mismatch.
  • Zero rows affectedReject as stale: explicit result.
  1. Proposal targets version 12. Both paths begin with proposal P tied to record version 12. Active: Proposal P · version 12. New: Proposal P · version 12.
  2. Unsafe preflight succeeds. The unsafe path reads version 12, but the read and eventual write are separate operations. Active: Proposal P · version 12, Preflight reads version 12. New: Preflight reads version 12.
  3. Authoritative state advances. A concurrent writer commits version 13 after the preflight read. Active: Proposal P · version 12, Preflight reads version 12, Concurrent writer creates version 13. New: Concurrent writer creates version 13.
  4. Separated write is unsafe. An unconditional later write can apply the version-12 proposal after the row has advanced. Active: Proposal P · version 12, Preflight reads version 12, Concurrent writer creates version 13, Later unconditional write. New: Later unconditional write.
  5. Conditional update reaches the database. The safe path submits the record id, expected version 12, label mutation, and version increment as one update. Active: Proposal P · version 12, Concurrent writer creates version 13, Conditional UPDATE. New: Conditional UPDATE.
  6. Database rejects the stale proposal. The database rechecks the predicate against version 13, affects zero rows, and the application returns stale rejection. Active: Proposal P · version 12, Concurrent writer creates version 13, Conditional UPDATE, Database rechecks version 13, Zero rows affected, Reject as stale. New: Database rechecks version 13, Zero rows affected, Reject as stale.

Represent uncertain external outcomes

A side effect is an observable change outside a function’s returned value: writing a record, sending a message, charging a card, or publishing a file. A database transaction can group local changes so they commit together or roll back together, but it does not automatically include an unrelated remote API. The local record and the remote system therefore occupy different transaction boundaries.

A timeout creates partial failure when the caller lacks enough information to classify the whole operation. The remote service may have completed an effect while its response was delayed or lost. Cancellation likewise does not roll back completed changes. A useful result type distinguishes confirmed success, confirmed rejection, and unknown outcome; collapsing unknown into failure invites an unsafe duplicate operation.

Remote completion can coexist with caller uncertainty

Example

A deadline describes what the caller observed, not whether the remote effect occurred.

1 / 3 · Send identified request

The caller creates operation op-42 and sends it to the remote service.

The caller sends one identified operation. The remote service completes its effect, but no confirmation reaches the caller before its deadline. The final caller state is unknown, so an unconditional new operation could duplicate the effect. Step spacing is not a time scale.
Read the diagram as text
  • Caller. Application component awaiting confirmation.
  • Operation op-42. Stable logical identity retained across status checks or safe retries.
  • Remote service. Authority over the external effect.
  • Remote effect completed. The external change exists even though confirmation is absent.
  • Caller outcome unknown. The deadline passed without authoritative confirmation.
  • CallerOperation op-42: creates identity.
  • Operation op-42Remote service: request.
  • Remote serviceRemote effect completed: commits effect.
  • Operation op-42Caller outcome unknown: deadline without confirmation.
  1. Send identified request. The caller creates operation op-42 and sends it to the remote service. Active: Caller, Operation op-42, Remote service. New: Caller, Operation op-42, Remote service.
  2. Remote effect completes. The remote service adds a completed effect for op-42; the caller has not received confirmation. Active: Caller, Operation op-42, Remote service, Remote effect completed. New: Remote effect completed.
  3. Deadline expires. The caller adds an unknown outcome. Remote completion remains visible as a separate fact. Active: Caller, Operation op-42, Remote service, Remote effect completed, Caller outcome unknown. New: Caller outcome unknown.

Safe repetition requires a contract

Idempotency means that repeating the same logical operation does not add another effect. It requires a stable operation identity and enforcement by the receiving boundary; merely logging a key is not enough. Stripe, for example, documents provider-specific behavior that stores the first executing request’s result for an idempotency key and rejects parameter mismatches. Other services can have different retention and concurrency rules. When the outcome is unknown, preserve the operation identity and reconcile against authoritative provider state before deciding whether another attempt is safe.

Simple synchronous code is easy to follow when success and failure are promptly confirmed. Explicit pending and unknown states add complexity, but they become necessary when external effects can outlive the caller’s observation. Durable retries, checkpoints, scheduling, and long-running recovery belong to Agent Runtimes and Harness Engineering.

Testing the right claims

Match checks to claims

A test oracle is the rule used to decide whether an observed result satisfies an expectation. The relevant distinction between software testing and model evaluation is the claim supported by that oracle—not whether the run uses a real model, a substitute, exact code, or a model judge. A software test can call a real model to exercise parsing. An evaluation can use deterministic code to score an exact task outcome.

Choose an observation that matches the claim.
ClaimExerciseOracleWhat remains unknown
Invalid data is never committed in these casesAcceptance and storage pathRejected result and unchanged authoritative stateCases and invariants not exercised by the suite
The adapter handles the provider interactionSerialization, response handling, and documented errorsExpected request and accepted or rejected responseUsefulness of the provider’s model answers
A selected user path is connectedApplication wiring and user-visible boundaryExpected observable outcomeOther paths and production conditions
Classifications are useful for the intended taskRepresentative labeled cases, repeated where behavior variesTask-specific metrics and review criteriaPerformance outside the evaluated distribution

A regression is an unintended loss of behavior or performance that was previously supported. A changed mean score, a failed assertion, or one different answer is not automatically a regression; the interpretation depends on the baseline, expected variability, and acceptance criterion. Nathan Sobo’s CI and stochastic-evals talk shows broad coding-agent failures being narrowed into focused stochastic checks and then conventional tests for deterministic surrounding defects. Reported run counts are local acceptance choices, not universal reliability guarantees.

Evals and Benchmarks develops representative task selection, graders, human assessment, uncertainty, and comparison. This chapter’s narrower concern is preserving the boundary: an application test supports the properties it asserts, while evidence about useful model behavior must cover the intended task and conditions.

Control dependencies in focused tests

A unit test is a focused check of a small unit’s behavior. A fixture provides preparation, cleanup, or stored test data; a suite groups checks; and a runner executes them and reports outcomes. Explicit dependencies let the test provide a model response, clock value, or external failure rather than waiting for a live system to produce the desired condition.

A test double replaces a real dependency. A stub supplies predetermined answers. A fake implements a simplified working version, such as an in-memory repository. These checks establish how the application responds to the supplied behavior; they do not establish that the real dependency will produce it, or how often it will do so. Focused real-implementation checks must cover that separate risk.

Test observable obligations

A compact table-driven suite can exercise the acceptance boundary without depending on fresh inference.
Supplied dependency resultExpected application resultState assertion
Valid label for version 12AcceptedLabel changes and version advances once
Malformed label recordRejected as invalid outputRecord remains unchanged
Provider timeoutUnknown or unavailable resultNo fabricated label is stored
Valid label based on stale version 12Rejected as staleCurrent version 13 remains unchanged

Assertions should target public behavior callers rely on. Exact text equality is appropriate when exact text is the contract; it is brittle when punctuation or explanatory wording is irrelevant. Likewise, interaction assertions about internal call order should be used only when that order is itself an obligation.

Vary inputs, keep the oracle explicit

Property-based testing expresses an executable property and generates many inputs to check it. Koen Claessen and John Hughes introduced QuickCheck at ICFP 2000 to make controlled generation and executable properties practical in Haskell. A useful property here might say that any rejected proposal leaves the record unchanged. Generators, distributions, and the property itself can still be incomplete or wrong; finite successful cases are evidence, not a proof.

Exercise real integration boundaries

An integration test exercises collaborating components. A contract test checks that an implementation satisfies an agreed interaction. An end-to-end test exercises a selected complete path through the application. These categories overlap, but they answer different boundary questions. None replaces focused tests that localize failures cheaply.

Check both sides of an interaction

A substitute can encode an obsolete assumption while every isolated test passes. Pact illustrates a paired mechanism: consumer tests check the request a client sends and how it handles a supplied response; provider verification sends those expected interactions to the provider and compares the actual response. Passing those interactions does not establish complete workflow behavior or model-answer quality, and it does not imply that an arbitrary hosted model provider supports Pact.

Run checks according to the boundary that changed.

  • Provider or SDK changeExercise request serialization, streaming, response parsing, and documented error handling through the real adapter boundary.
  • Persistence changeExercise the real database’s constraints, transaction behavior, and conditional-update semantics with isolated test state.
  • Application wiring changeExercise a small complete path through the user-visible boundary, including the final persisted or rendered result.
  • Model behavior changeRun task evaluations in addition to integration checks; protocol compatibility does not establish answer usefulness.

Higher-fidelity tests can detect configuration errors, stale assumptions, and missing connections, but they are slower, less isolated, and more dependent on shared infrastructure. Replit described visually plausible “painted doors”—for example, a button without a connected handler or a screen backed by mock rather than persisted data—and used programmatic and browser checks to expose them. The three pillars of autonomy talk is a concrete example of why code completion claims need outcome checks.

Reproduction and diagnosis

Replay the failed boundary

Investigating a model-containing failure involves two different reproduction goals. Regenerating asks the provider for another answer. Replaying supplies the saved historical answer to the downstream application. Replay can reproduce a parser, policy, or state-transition defect even when the provider cannot regenerate the original text.

Execution context for replay

Capture the inputs needed by the failed path, not merely the final error message.

  • Dependency exchangeRelevant request and exact returned response, including the failure mode being investigated.
  • Application stateThe smallest initial state, clock values, and configuration required to reach the same boundary.
  • Implementation identityCode revision, instructions, schema, dependency versions, and relevant feature configuration.
  • Model contextModel identifier and generation settings, retained as provenance rather than a guarantee of exact regeneration.

VCR.py provides a concrete HTTP record/replay mechanism: it records an interaction and later supplies the saved response for a matching request. Its none recording mode rejects unmatched requests instead of silently contacting the service. Applied to a model adapter, this makes the response a fixed fixture while preserving the normal downstream processing path. Database state, clocks, scheduling, and external mutations remain separate dependencies that must also be controlled.

A seed and fixed request parameters may improve repeatability but do not necessarily reconstruct a hosted response; an archived OpenAI example explicitly documented remaining variation even with a matching system fingerprint. Replayed fixtures can also contain private prompts, credentials, or user data. Filtering must be configured deliberately, must preserve the failure-inducing information, and does not by itself prove the fixture safe. Access should follow the sensitivity of the captured data. Observability covers collecting and connecting execution records in operating systems.

Test explanations of a failure

A symptom is an observation, not an explanation. Debugging proceeds by proposing a falsifiable hypothesis, choosing an intervention that distinguishes it from alternatives, and observing a result that could reject it. Recent changes help generate hypotheses, but temporal proximity does not prove causation. Diagnostic logging or resource changes can also alter latency and races, so the experiment itself may be a confounder.

A discriminating experiment

Suppose a recorded response fails while the parser handles a streamed field. Keep the response, initial state, and code revision fixed; vary only the suspected handling rule.
ConditionChanged factorPossible observationInterpretation
Baseline replayNoneFailure repeats at the same boundaryThe fixture reproduces the downstream symptom.
Replace only the suspected parser ruleParser ruleFailure disappears and the expected state is producedSupports the parser hypothesis, subject to regression checks.
Replace only the suspected parser ruleParser ruleFailure remains unchangedContradicts the claim that this rule alone caused the symptom.
Call the live model againDependency response and possibly provider stateA different response succeedsDoes not discriminate between parser repair and changed input.

Reduce without changing the failure

Failure reduction removes irrelevant input while preserving the same failure predicate. Andreas Zeller and Ralf Hildebrandt’s February 2002 paper, Simplifying and Isolating Failure-Inducing Input, describes ddmin, which repeatedly tests subsets until no single remaining element can be removed while retaining the failure. This yields a one-minimal case, not necessarily the globally smallest input and not an explanation of the defective code.

Once the defect is understood, preserve a focused regression test that fails before the repair and passes afterward. Then run broader relevant checks because a local fix can damage other behavior. A single improved model response still does not establish a model improvement; variable behavior requires repeated comparison under the evaluation design appropriate to the task.

Controlled change

Make changes reviewable

Version control records changes to files over time so particular versions can be compared and recovered. Refactoring changes internal structure while preserving observable behavior. A feature change deliberately changes behavior; a bug fix restores or establishes intended behavior. Separating substantial refactoring from behavior changes gives reviewers a clearer claim to examine.

A reviewable change is conceptually focused, not constrained by a universal line count. It includes the tests and usage context needed to understand its consequences while leaving the system working after integration. Review must inspect contracts, edge cases, concurrency, side effects, complexity, and test quality. Passing assertions are evidence only if they would fail for the broken behavior that matters.

Validation should follow the changed responsibility; one change can require several rows.
ChangePrimary review questionRelevant checks
Domain ruleDoes the new rule preserve stated invariants and failure behavior?Focused unit and property-based tests
Provider interface or schemaDo both sides still agree on requests, responses, and failures?Contract and adapter integration checks
Database transitionAre atomicity, compatibility, and concurrency assumptions valid?Real database-boundary tests
Prompt or modelDoes behavior improve without unacceptable regression on intended tasks?Task-specific evaluations plus unchanged integration checks
Application wiringDoes the selected user path reach the visible or persisted outcome?Complete-path test

Continuous integration checks the combined revision frequently so interactions between changes are discovered while their causes remain recent. Fowler and Foemmel’s 2000 account required more than a daily build: developers integrated often, and failures were repaired or backed out. Matt Pocock’s software-fundamentals talk applies the same feedback principle to agent-assisted work: make a small change, check it, and reconsider the design before producing a large unverified batch. Test-first development is one useful practice, not a universal requirement.

Identify what was tested and released

A passing check describes the exact inputs and artifacts it exercised. A release artifact is a produced item used to run or configure the released application. Useful release identity therefore extends beyond a source commit to packaged code, configuration, instructions, schemas, dependency versions, and model selection. A moving label such as canary is not an immutable version.

A release record connects each behavior-affecting input to an identity and relevant evidence.
Input or artifactRecorded identityEvidence tied to it
Application sourceCommit or immutable revisionBuild, focused tests, and integrated checks
Packaged executableUnique version and content hashRelease and system tests on that artifact
Prompt and policy configurationImmutable configuration versionBehavioral evaluations and policy checks
Schemas and dependenciesResolved versionsCompatibility and integration checks
Hosted modelProvider, model identifier, and platformTask evaluations and availability record
Mutable runtime stateCurrent authoritative versionCompatibility and recovery checks; not part of the build artifact

A reproducible build lets another party recreate identical specified artifacts from the same source, build environment, and instructions, commonly comparing bytes or hashes. Recording a source revision alone is insufficient because dependency versions, flags, and environment variables can affect the artifact. Identical artifacts still do not reproduce databases, clocks, remote services, or hosted inference.

Behavior-affecting configuration can change outside application code. A Braintrust workshop demonstrated changing managed model parameters without a code edit while still recommending version-control and synchronization discipline; see Shipping Complex AI Applications. The product details are historical, but the engineering point is durable: evidence must identify the configuration actually evaluated and released.

Exposure and recovery

Limit exposure and stop new work

A canary exposes a candidate change to a limited portion of use for a limited period before broader promotion. Candidate and control metrics should be examined separately because aggregate service metrics can hide a candidate failure. Population, duration, and load must exercise relevant conditions; there is no universal safe percentage or observation period.

A feature flag controls availability or selects a variant through runtime configuration. Define user-relevant promotion and stop conditions before exposure. A kill switch is a control intended to stop further selected behavior, but it works only at the decision points where the application evaluates it. Resolving a switch only when a session begins can leave an existing conversation unaffected until another session.

These controls solve different problems and have different limits.
ControlDecision affectedRequired observationOutside its reach
Canary allocationWho receives the candidateCandidate-versus-control outcomes under relevant conditionsHarm already caused to an exposed request
Variant flagWhich configured behavior runsBehavior and failure measures by variantEffects completed before the flag change
Kill switchWhether selected future work may proceedActivation, propagation, and decision-point enforcementAn already executing tool or completed external effect unless separately supported

Runtime controls need drills and lifecycle ownership. Configuration changes can break a dormant kill switch; temporary rollout flags can become undocumented dependencies; interacting variants need combination testing based on valid configurations. Temporary rollout flags should have owners and removal conditions, while permanent emergency controls require continuing verification. The feature-flags talk supplies practitioner examples, but its suggested numeric thresholds are not universal limits.

Restore software without erasing effects

Rollback restores a previously identified software or configuration version. It requires that the earlier artifact still exists, its dependencies remain available, and it can operate safely on current persisted state. Amazon’s rollback-safety report illustrates a new writer producing data an original version cannot read: restoring that original executable would add failures rather than recover service.

Hosted dependencies create another limit. A recorded model identifier does not guarantee that the provider or every partner platform will continue serving it. Providers can deprecate and retire models on different schedules. A rollback plan that depends on an unavailable model is only a historical record, not an executable recovery path.

Recovery has separate responsibilities

Restoring software changes future execution; it does not erase a sent message, restore an overwritten record, or prove whether a timed-out payment occurred. Reconciliation determines the authoritative outcome and aligns local state with it. Compensation performs a new, business-specific action that counters completed work. Compensation is not database rollback: it can preserve intervening changes, incur fees, produce a different final state, and fail in turn. Irreversible effects need an acceptable remedy or human escalation rather than a claim that they were undone.

Rollback changes future execution, not history

An earlier release is usable only when it remains available and compatible with current state; completed effects need a separate recovery path.

The retained release can restore serving only if its dependencies are available and it can read current persisted state. Restored serving continues from current state rather than erasing it. Completed or uncertain external effects flow to reconciliation, compensation, or manual remedy; there is deliberately no rollback edge that deletes them.
Read the diagram as text
  • Candidate release. The version whose behavior requires mitigation.
  • Retained earlier release. Immutable artifact and configuration proposed for restoration.
  • Available dependencies. Required runtimes, packages, and hosted models still exist.
  • Current persisted state. Data as it exists after candidate execution.
  • Restored serving. Earlier release running against current compatible state.
  • Completed or uncertain effects. Messages, payments, writes, or other external outcomes already outside release control.
  • Reconcile or remedy. Determine authoritative outcomes and compensate or escalate where supported.
  • Candidate releaseCurrent persisted state: left current data.
  • Candidate releaseCompleted or uncertain effects: may have caused effects.
  • Retained earlier releaseRestored serving: condition: artifact retained.
  • Available dependenciesRestored serving: condition: still available.
  • Current persisted stateRestored serving: condition: state compatible.
  • Completed or uncertain effectsReconcile or remedy: corrective action.
  • Restored servingReconcile or remedy: future work separated.

A justified recovery decision therefore combines three questions. Can further harmful work be stopped at the relevant decision boundary? Can a retained release run against today’s state and dependencies? Which completed or uncertain effects need reconciliation, compensation, or manual remedy? Treating these as separate obligations preserves the chapter’s central principle: software can make precise guarantees, but only within the boundaries those guarantees actually cover.

Open questions

  1. How can teams specify semantic obligations precisely enough for strong automated checking without merely reproducing the same faulty implementation in the oracle? Progress would combine independently reviewable specifications, calibrated evaluators, and evidence that the checks reject realistic incorrect behavior.

  2. How should test suites allocate effort between controlled substitutes, real provider boundaries, and complete application paths as providers and models evolve? The difficulty is balancing fidelity, cost, diagnostic clarity, and external-service instability; progress would produce risk-based strategies validated across real changes rather than a universal test ratio.

  3. How can replay systems preserve enough failure-inducing context while minimizing sensitive data and preventing repeated external effects? Progress would provide tested minimization, access-control, and side-effect-isolation techniques that retain the original failure predicate.

  4. How can rollback readiness be established when hosted models, mutable data formats, and irreversible external effects evolve independently? Progress would combine continuous compatibility checks, executable retained alternatives, and explicit reconciliation or remedy plans for effects software restoration cannot reverse.

Follow the curated reading path through the speakers and demonstrations behind this entry.

19 min

AI Engineer Summit 2023 · 2023

Pragmatic AI With TypeChat

Daniel Rosenwasser

Cited in this entry

Daniel Rosenwasser demonstrates how one type definition can guide generated records, validate them, and return diagnostics without claiming semantic correctness.

Watch talk
19 min

AI Engineer World's Fair 2026 · 2026

Agents Need Feature Flags

Sachin Gupta

Cited in this entry

Sachin Gupta examines runtime variants, kill-switch decision points, staged exposure, and the maintenance failures that can undermine those controls.

Watch talk

Explore more talks

The rest of the library, beyond the curated path. Cited talks support this entry; reviewed transcripts were processed in full. Metadata candidates have not been reviewed as sources or verified as topic members.

38 matching talks

TalkSpeakerEventYear
Michael FesterAI Engineer World's Fair 20252025
Respect The Process

Transcript reviewed

Andrew DumitAI Engineer World's Fair 20262026
Omar KhattabAI Engineer World's Fair 20252025
Dan MasonAI Engineer World's Fair 20252025
DottaAI Engineer World's Fair 20262026
Erik MeijerAI Engineer World's Fair 20262026
Vinoth GovindarajanAI Engineer World's Fair 20262026
Sandipan BhaumikAI Engineer Europe 20262026
Vikash Agrawal, LindaAI Engineer World's Fair 20252025
Fuzzing in the GenAI Era

Transcript reviewed

Leonard TangAI Engineer World's Fair 20252025
Giran Moodley, Mayan Soni, Oussama Hafferssas, Mayank SoniAI Engineer Europe 20262026
Niklas NielsenAI Engineer Summit 20232023
Sumaiya ShrabonyAI Engineer World's Fair 20262026
Lukas PeterssonAI Engineer World's Fair 20262026
Eugene YanAI Engineer World's Fair 20262026
Lukas BiewaldAI Engineer World's Fair 20242024
Ibragim BadertdinovAI Engineer Europe 20262026
How to Kill the Code Review

Transcript reviewed

Ankit JainAI Engineer World's Fair 20262026
Kyle MisteleAI Engineer World's Fair 20262026
Tomas ReimersAI Engineer World's Fair 20252025
Jared JoselowitzAI Engineer World's Fair 20262026
Nishant GuptaAI Engineer World's Fair 20262026
Jason LiuAI Engineer World's Fair 20242024
Bennet FennerAI Engineer Europe 20262026
Vibe Engineering Effect Apps

Transcript reviewed

Michael ArnaldiAI Engineer Europe 20262026
Samuel ColvinAI Engineer World's Fair 20252025
Mason EggerAI Engineer World's Fair 20252025
Adam TerlsonAI Engineer Summit 20252025
Misha Kaletsky, Jonas TemplesteinAI Engineer Europe 20262026
Evals Are Not Unit Tests

Transcript reviewed

Ido PesokAI Engineer World's Fair 20252025
Josh AlbrechtAI Engineer World's Fair 20252025
Michele CatastaAI Engineer Code 20252025
Michal CichraAI Engineer Europe 20262026
Nik CaryotakisAI Engineer Summit 20252025
Lawrence JonesAI Engineer Europe 20262026
Eugene Yan, Hamel Husain, Jason Liu, Dr Bryan Bischof, Charles Frye, Shreya ShankarAI Engineer World's Fair 20242024
Brooke HopkinsAI Engineer World's Fair 20252025
Rajat ShahAI Engineer World's Fair 20262026

References

Coverage and source review
Processed transcripts
42 processed in full · 4 in the curated path
Automated source review
Passed
Metadata candidates
0 unreviewed; not verified topic membership
Corpus version
1bd8e407b26a07b33815594e1b2db5f41827119a2b3cb6fbf240f9fc571fc767

Automated review checks source support; it is not publication approval.

A synthesis of selected conference talks and technical references. Citations link to the source material; they do not imply that every talk on this subject is included.

  1. Google: What is Machine Learning?

    Machine learning trains software to make predictions or generate content using data. Google's rainfall example contrasts explicitly implemented physical equations with relationships learned from weather observations. This supports a brief distinction between programmed rules and learned predictions.

  2. On Engineering AI Systems that Endure The Bitter Lesson

    Put essential control flow, tool definitions, information-flow restrictions, and function composition in code where explicit structure is required.

  3. Hidden Technical Debt in Machine Learning Systems

    Sculley and colleagues explain why maintaining an ML system requires more than maintaining its model code. Data dependencies, configuration, feedback loops and downstream consumers can couple components whose code appears separate. Changing one model input can affect how other inputs influence predictions. They distinguish ordinary improvements such as clearer APIs and better tests from additional system-level work needed to manage learned behavior. Modular code remains useful, but cannot by itself guarantee that a model change has isolated behavioral consequences.

  4. An Axiomatic Basis for Computer Programming

    In October 1969, C. A. R. Hoare of Queen's University Belfast presented rules for reasoning about program behavior from assertions. His notation connects an initial condition, a program and a condition established on successful termination. Composition connects components when one's established result satisfies the next component's starting condition. The paper demonstrates a proof for division by repeated subtraction and argues that assertions can document routines and support replacing implementations while preserving their obligations. Hoare explicitly credits Floyd's earlier treatment of flowcharts.

  5. On the Criteria To Be Used in Decomposing Systems into Modules

    Parnas treats a module as an assigned responsibility rather than necessarily a subroutine. His keyword-index example contrasts modules organized around processing stages with modules that hide storage and other design decisions. In the latter arrangement, changing the representation of stored lines need not change its callers. He recommends beginning with difficult decisions or decisions likely to change, then concealing each behind an interface. The paper also warns that a naive implementation can introduce procedure-call overhead.

  6. Continuous Integration (original version)

    Martin Fowler and Matthew Foemmel's September 10, 2000 account describes continuous integration on a Thoughtworks project: developers integrate frequently, and an automated process retrieves sources, builds the application and runs tests against the combined result. The motivation was to discover interactions between developers' changes while the relevant changes were still small and recent. Merely running a daily build without frequent integration does not provide the same feedback. Their process records successful build identities and requires repairing or backing out changes when integration fails.

  7. Introducing TypeChat

    Microsoft announced TypeChat as an experimental library on July 20, 2023, to connect natural-language requests with existing applications. It describes checking generated JSON against TypeScript definitions using the compiler and returning validation errors for repair. Its sentiment example permits three labels and branches explicitly between translation failure and successful data. The application can perform further processing or user validation after receiving a well-typed response.

  8. TypeScript Handbook: Everyday Types

    Types describe admissible values: boolean covers true and false, while a union admits values from its member types. Function annotations describe accepted arguments and returned values. An interface names an object type. Ordinary type aliases do not create distinct categories: the handbook's alias named UserInputSanitizedString still accepts an arbitrary string. Consequently, naming a type after a desired property does not establish that the property was checked.

  9. Applying Design by Contract

    A precondition is an obligation the caller must establish before invoking a routine. If it holds, the supplier owes the stated postcondition on successful completion. A class invariant describes consistent observable object states: creation establishes it and exported routines preserve it between entry and exit; it need not hold during every internal instruction. The caller can establish a precondition by reasoning from prior guarantees rather than necessarily testing it again. Application inference: a generated typed record supplies candidate data, not proof of caller authorization, business postconditions, or state invariants. The application must establish relevant obligations before acting and verify promised results or represent failure explicitly.

  10. Applying Design by Contract

    Bertrand Meyer's October 1992 article presents contracts as practical reliability guidance for reusable object-oriented components, building on systematic programming and abstract data types. It also identifies a modularity tradeoff: excessive routine calls fragment code, while too few leave individual routines overly complex.

  11. Zod: Basic usage

    Zod validates runtime input against a schema. Its parse method returns validated data or throws a validation error identifying failed checks. safeParse instead returns a discriminated result: a success flag identifies either validated data or an error. The documentation demonstrates branching on that flag before accessing the corresponding value. Static types can also be inferred from the schema, keeping the declared shape and runtime checks connected.

  12. TypeScript Handbook: The Basics

    TypeScript removes type annotations when producing JavaScript; the annotations do not change runtime behavior. Its documented compilation example retains the function body but removes parameter types. Application implication: annotating a parsed model response with a TypeScript interface does not install runtime checks on incoming values.

  13. JSON Schema: Objects

    A schema can constrain object structure and field types, but declaring a property does not make it required. The required keyword enforces presence, while additionalProperties can reject unrecognized fields. These checks belong in application code when accepting structured model proposals. A valid object can still name the wrong account or contain an unsupported answer: structural validation checks the declared data contract, not external facts or permission to perform an operation.

  14. Pragmatic AI With TypeChat

    TypeChat uses the same types to guide model output and validate the resulting data.

  15. Pragmatic AI With TypeChat

    Compiler diagnostics can become feedback for a subsequent model repair request.

  16. Azure Architecture Center: Design for evolution

    Cohesion means grouping functionality that logically belongs together. Loose coupling means one service can change without requiring another to change. Microsoft recommends keeping domain rules within the component responsible for them and separating domain logic from infrastructure such as messaging and persistence. Splitting an application into services does not automatically remove tight coupling.

  17. Software Engineering at Google: Test Doubles

    A test double substitutes for a real dependency. Dependency injection creates a substitution point by passing a dependency to a component instead of constructing it internally; the book demonstrates this without requiring a framework. Controlled substitutes can return fixed values or trigger rare errors without contacting an external service. Their fidelity is how closely they resemble the real implementation. A test can establish the application's response to supplied behavior while leaving the real dependency untested. The authors recommend supplementing such tests with checks using real implementations and warn that excessive stubbing creates brittle tests.

  18. "Software Fundamentals Matter More Than Ever" — Matt Pocock

    Apply John Ousterhout's deep modules: substantial functionality behind simple interfaces, rather than many shallow modules with complex interfaces.

  19. Building Reliable Support Agents Using the Effect TypeScript Library - Michael Fester

    Dependency injection can make service provisioning difficult to trace across layers and subsystems.

  20. React: Keeping Components Pure

    A pure function returns the same result for the same inputs and does not change pre-existing objects or variables. React's example shows how reading and incrementing an external counter makes results depend on call order. Passing the needed value as an explicit input removes that hidden dependency.

  21. Functional Core, Imperative Shell

    Gary Bernhardt describes a Twitter client whose functional core handles values and decisions while an imperative shell performs terminal, database and network operations using those results. Separating these responsibilities makes the functional pieces independently testable and leaves fewer conditionals in the code that performs effects.

  22. Design by Contract and Assertions

    A precondition states the caller's obligations before an operation; a postcondition states the implementation's obligations on successful return. A class invariant defines valid object states and generally must hold before and after exported operations, not necessarily during every internal statement. For a state transition from s to s', the teaching shorthand is: assuming I(s) and P(s,a), successful return must establish Q(s,a,s') and I(s'). Postconditions can relate new values to old values. Eiffel's runtime assertion checks are configurable and detect violations on executed calls.

  23. PostgreSQL 18: Transaction Isolation

    Under PostgreSQL Read Committed isolation, successive reads can observe different committed states. An UPDATE encountering a concurrently updated row waits and then rechecks its WHERE condition against the committed row version. Constructed application example: accept a proposed label only through an update matching both the record identifier and its expected version, and increment that version in the same update. If another writer has advanced the version, the stale proposal cannot satisfy the predicate. A separate preflight read does not provide this protection.

  24. Your Agent Didn’t Fail. Your Harness Did.

    Provide one ordered commit path per mutable state boundary while allowing independent work to run concurrently.

  25. PostgreSQL 18: Transactions

    A transaction groups database updates into an all-or-nothing operation. Other transactions do not observe its unfinished changes; committing makes the grouped changes visible together. BEGIN and COMMIT delimit a transaction block, while ROLLBACK discards its changes. Applied to runtime records, an operation result, its status transition, and newly pending work can be committed together when they reside in the same transactional database.

  26. gRPC lifecycle: cancellation is not rollback

    Client and server can disagree about an RPC's success: the server may finish while its response arrives after the client's deadline. gRPC explicitly warns that cancellation does not roll back changes already made. Application implication: cancellation during a mutation may leave an unknown outcome. Retain an operation identifier, query authoritative status or reconcile the resulting state, and use an idempotent retry contract before resubmitting. If an effect must be reversed, that requires a separate supported compensating operation rather than assuming cancellation undid it.

  27. Resolving an ambiguous payment request

    A timeout can leave the client unable to tell whether Stripe received or executed a request. Stripe documents retrying with the same key and parameters until a server result is obtained, using backoff. An HTTP 500 remains indeterminate: side effects may exist even though the cached response stays unchanged. Stripe may reconcile partial mutations and emit webhook events for resulting objects. Supplying a local operation identifier in metadata lets the application correlate these objects with its own pending operation. Engineering consequence: preserve pending state until authoritative provider evidence resolves it; do not infer failure solely from a timeout.

  28. Idempotent requests

    Stripe stores the first executing request's status code and response body for an idempotency key, including failures such as HTTP 500, and returns the stored result on retries. Parameter mismatches are rejected. A request rejected before execution because of validation or a conflict with a concurrently executing request does not create a saved idempotent result and can be retried. Keys may be pruned once at least 24 hours old; reuse after pruning starts a new request. Thus an in-progress conflict, a stored failure, and an expired key have different recovery semantics.

  29. Demystifying evals for AI agents

    An agent evaluation separates a task and its success criteria from repeated trials, execution transcripts, graders, and final environment outcomes. A booking claim in a transcript is different from an actual reservation in the database. The system under test includes both model and agent harness. Code-based checks suit precise state or test assertions; model graders cover more open-ended properties but require calibration; human review helps establish the standard. Capability suites explore difficult behavior, while regression suites protect behavior that already works.

  30. QuickCheck: Executable Properties and Generated Inputs

    Property-based testing expresses a general, executable predicate over inputs, then generates many concrete cases and checks that predicate. QuickCheck separates the property from generators whose distributions and admissible inputs the programmer controls. Conditional properties can restrict applicable cases, but excessive discarded cases can make testing ineffective. Application examples include checking that serialization round-trips preserve supported values, validators reject generated violations, or protocol transitions preserve an explicit state invariant. These use deterministic assertions as the test oracle. A model may generate inputs, but model-judged fuzzing additionally depends on the judge's correctness; generating unusual examples alone does not define an executable property. Passing finite tests supplies evidence, not a proof over all inputs.

  31. Software Engineering at Google: Unit Testing

    Tests should exercise the public behavior callers rely on rather than private methods or incidental storage formats. The book contrasts assertions about serialized internals with assertions about resulting account balances. It recommends adding the missing case when fixing a bug and preserving existing tests during behavior-preserving refactoring. Tests that fail after an unrelated implementation change can impose maintenance work without identifying a real defect. Applied to model output, exact text equality is appropriate only when that exact text is part of the required behavior; otherwise the assertion should target the relevant property.

  32. CI in the Era of AI: From Unit Tests to Stochastic Evals

    Narrow an end-to-end eval into a focused stochastic test, then isolate deterministic defects in the surrounding software.

  33. CI in the Era of AI: From Unit Tests to Stochastic Evals

    Repeat focused model evals and gate the build on an explicit pass threshold.

  34. unittest — Unit testing framework

    A test case checks a particular response to specified inputs. A test suite groups cases or other suites for execution together. A fixture supplies preparation and cleanup, such as a temporary database or server. A runner executes tests and reports outcomes. Python's published example separately checks expected values, Boolean conditions, and expected exceptions; its command interface can select a module, class, or individual method.

  35. Testing on the Toilet: Know Your Test Doubles

    A stub supplies predetermined answers so a test can exercise a chosen condition. A fake implements a simplified version of an interface, such as an in-memory database. Google's authentication example makes the distinction concrete: the stub returns the configured authentication result, whereas the fake changes its result after a user is added to its stored authenticated-user set. A mock instead verifies expected interactions.

  36. pytest: How to parametrize fixtures and test functions

    Parametrization runs the same test function with multiple explicitly supplied argument sets. pytest's published example pairs each input with an expected result and identifies the particular failing case. This provides a compact mechanism for table-driven checks of valid records, rejected records and boundary conditions.

  37. QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs

    Koen Claessen and John Hughes of Chalmers University presented QuickCheck at ICFP 2000. They sought to reduce manual testing work with a lightweight tool that made executable properties and controlled input generation practical within Haskell.

  38. Software Engineering at Google: Larger Testing

    Joseph Graves explains why isolated tests can pass while collaborating components fail. A substitute may encode an incorrect assumption about its dependency or become stale when the real implementation changes. Startup configuration and its compatibility with a binary also lie beyond ordinary isolated checks. Larger tests exercise a selected system, seed data, perform actions and verify behavior. Increasing similarity to production improves fidelity but can introduce shared-state interference, slower execution and greater maintenance cost. The chapter recommends keeping tests as small as possible while retaining the fidelity needed for the risk.

  39. Pact: How Pact works

    A consumer contract test checks whether client code sends the expected request and correctly handles a supplied response. Pact records these interactions, then provider verification sends the requests to the provider and compares actual responses with the consumer's expectations. Provider states establish necessary preconditions, such as an existing user. These complementary checks test whether the substitute-based assumptions agree with the provider for the described interactions.

  40. The 3 Pillars of Autonomy – Michele Catasta, Replit

    Autonomous testing addresses 'painted doors': apparently complete features whose behavior or data connections are missing.

  41. The 3 Pillars of Autonomy – Michele Catasta, Replit

    Replit describes combining programmatic application inspection with browser interaction and a screenshot-based computer-use fallback.

  42. VCR.py: Usage

    VCR.py records HTTP interactions and later supplies the saved response when the corresponding request is made. Its none recording mode rejects new requests instead of contacting the service. Applied to a model integration, replaying a captured response can reproduce downstream parsing and policy behavior without performing new inference. Re-recording obtains a new dependency response and changes the fixture.

  43. OpenAI Cookbook: How to make your completions outputs consistent with the new seed parameter

    OpenAI's November 6, 2023 example describes keeping the seed and request parameters fixed and comparing a system fingerprint representing model weights, infrastructure and other server configuration. It explicitly warns that responses can still differ even when those values match. A seed therefore offered improved repeatability, not a guarantee of reconstructing an identical historical response.

  44. What We Learned From A Year of Building With LLMs

    Associate traces with code, model, and prompt versions, and pin API model versions to reduce unexplained behavioral changes.

  45. Reproducible Builds: Definitions

    A reproducible build allows another party to recreate identical specified artifacts from the same source, build environment and instructions. Relevant inputs commonly include dependency versions, configuration flags and environment variables. Reproducibility is checked by comparing artifact bytes, commonly through cryptographic hashes. Recording a source revision alone therefore does not completely describe a reproducible build.

  46. VCR.py: Advanced Features

    VCR.py supports removing or replacing sensitive request headers, query parameters and posted fields before recording. Custom callbacks can modify or omit requests and responses, including sensitive response bodies. Request matchers determine whether an incoming request corresponds to a recorded interaction. These controls let debugging fixtures retain selected behavior without automatically retaining every credential or payload field.

  47. Google SRE: Effective Troubleshooting

    Troubleshooting proceeds from observations to possible explanations and tests that discriminate between them. Google recommends recording expected and actual behavior, preserving a reproducible case, examining data at component boundaries and injecting known inputs. Experiments must account for confounders: testing connectivity from a workstation can mislead when access differs from the application server. Diagnostic interventions can themselves change behavior, including logging that worsens latency or resource changes that alter races. Recent deployments and configuration changes help generate hypotheses but temporal correlation does not establish causation.

  48. Simplifying and Isolating Failure-Inducing Input

    Zeller and Hildebrandt automate the reduction of failure-inducing inputs through repeated tests. Their ddmin procedure removes parts while retaining the failure, stopping when no single remaining input element can be removed successfully. A related procedure isolates differences between passing and failing cases. The paper motivates this with Mozilla's burden of simplifying bug reports and demonstrates reductions of HTML and user actions. The purpose is to remove irrelevant circumstances so the remaining failure is easier to investigate.

  49. Pro Git: About Version Control

    Version control records changes to files over time so that particular versions can be recovered. It supports comparing revisions, identifying who changed something and restoring selected files or a project to an earlier recorded state. Its scope includes many kinds of files, not only program source code.

  50. Refactoring

    Martin Fowler defines refactoring as improving software's internal structure while preserving its observable behavior. The technique proceeds through small transformations, keeping the system working between steps. His account separates restructuring that prepares for a feature from subsequently adding the feature. Automated refactoring tools help, but small steps and frequent testing also support the practice without those tools.

  51. Google Engineering Practices: Small CLs

    Google defines an appropriately small change by conceptual focus: one self-contained change with related tests and enough context for review. A new API may need a usage example in the same change to make its consequences understandable. The guide recommends separating substantial refactoring from behavior changes and keeping the system working after each submitted change. It argues that focused changes are easier to review, reason about and roll back.

  52. Google Engineering Practices: What to look for in a code review

    Review should consider functionality, edge cases, concurrency, unnecessary complexity and the validity of tests. Google asks reviewers whether assertions would fail for broken behavior and whether implementation changes would cause misleading failures. Tests themselves require human assessment. User-facing changes may need a demonstration because their consequences are difficult to infer from a diff; races and deadlocks also require deliberate reasoning beyond simply running the code.

  53. "Software Fundamentals Matter More Than Ever" — Matt Pocock

    Use test-driven development (TDD) to constrain the agent to small steps within the available feedback rate.

  54. Google SRE: Release Engineering

    Google's described release process links binaries to source revisions and build identifiers, archives change reports with artifacts, and gives packages unique version identities. Continuous tests detect failures after source changes, while release tests run against the actual release revision, which can differ from mainline after selected fixes. System tests also exercise packaged artifacts. Configuration can be snapshotted and released alongside binaries while retaining separate package identities. A moving label such as canary is distinct from an immutable package version.

  55. Shipping complex AI applications | Braintrust & Trainline

    Managed prompts and parameters can enable shared editing without application code changes, but should retain version control and synchronization discipline.

  56. Google SRE Workbook: Canarying Releases

    A canary exposes a change to a limited portion of service use for a limited time and evaluates whether to expand it. Google recommends comparing candidate and control metrics separately, because aggregate metrics can hide candidate failures. Unacceptable differences should pause or reverse deployment or prompt investigation. Exposure size and duration must provide representative traffic, including relevant load conditions. Metrics should reflect user-visible problems, and acceptance criteria must balance missed defects against false alarms.

  57. Unleash: Feature flags

    Feature flags let an application control feature availability through configuration without changing its source. Unleash evaluates activation strategies for a particular environment and context, such as a user or segment. Variants select among feature versions, while kill-switch flags support degrading functionality. Temporary release flags also require cleanup: marking a feature complete does not change its active configuration, and the documentation distinguishes removing flag usage from archiving the flag.

  58. Agents Need Feature Flags

    Ship agent-wide and per-tool kill switches first, and ensure in-flight work checks them at the next decision point.

  59. Agents Need Feature Flags

    Flags require ongoing drills, lifecycle ownership, and interaction testing.

  60. Amazon Builders' Library: Ensuring rollback safety during deployments

    Restoring an earlier software version is safe only if that version can work with the state and protocols now present. Amazon illustrates a new version writing compressed data that the previous version cannot read: restoring the old executable would introduce failures. Its staged format-change example first prepares readers, then activates new writers. After activation, rollback can return to the prepared version but not necessarily the original version. The report emphasizes verifying compatibility and completed deployment stages instead of assuming that individually working versions can coexist or replace each other safely.

  61. Continuous deployment — AWS Prescriptive Guidance

    AWS recommends staged model validation using offline tests, defined promotion metrics and runbooks, and the ability to switch between versioned models. It defines rollback as reverting to a previous deployment version when errors or unexpected behavior arise. Shadow evaluation runs a candidate alongside the existing model while the earlier model continues supplying production outputs.

  62. Claude Platform Docs: Model deprecations

    Anthropic distinguishes deprecated models, which remain functional pending retirement, from retired models, whose requests fail. Partner-operated platforms can have different retirement schedules. It advises testing applications with replacement models before retirement. Consequently, retaining an old model identifier in a release record does not establish that the corresponding service will remain available for rollback or reproduction.

  63. Compensating Transaction pattern

    Compensation performs new, business-specific actions to counter completed steps of an eventually consistent workflow. It differs from transaction rollback: intervening concurrent work must be preserved, the exact original state may be unattainable, and cancellation may incur charges. Record completed steps and the information needed to compensate them. Compensation order need not exactly reverse execution, and some steps can run in parallel. Compensation can itself fail, so persist progress, resume from failure, and make retryable steps idempotent. Where automated recovery is impossible, alert an operator with diagnostic information. For irreversible effects, an application must define an acceptable remedy or escalation rather than claim the action has been undone.

  64. Your Agent Didn’t Fail. Your Harness Did.

    Trace one real run from trigger identity through inherited state, authority, execution attempts, and surviving external evidence.

  65. "I've never seen anything scarier than an LLM with tool calls." — Erik Meijer aka @HeadinTheBox

    The speaker argues that broad judgments such as whether an answer is safe or a question is proper lack the mathematical specification needed for formal proof.

  66. LangGraph Functional API: deterministic resumption and idempotency

    Functional API resumption restarts the entrypoint and restores completed task and subgraph results from checkpoints. Ordinary entrypoint code runs again. Put randomness, clock reads, model calls and individual side effects inside tasks so persisted results can be reused. Keep task and interrupt ordering consistent with the recorded execution. A task that started but did not finish can execute again, including when an external effect occurred before its result was saved. Checkpointing therefore does not replace idempotency keys or checks for previously completed effects. Reusing a saved model result preserves that recorded value; calling the model again is a new inference, not reconstruction of an identical historical response.