Overview of MCSEP
MCSEP is a proposed workflow for developing software with agents or humans while keeping requirements, architecture and release decisions anchored in checkable evidence.
In a nutshell: A human describes the desired change (the feature, the refacto...) and approves its behavioral contract. Agents propose design, write code and investigate failures. Model checkers, proof checkers, compilers and test harnesses evaluate explicit claims. A release gate checks whether the required evidence exists and passes.
The agent should propose, but the verification systems should reject violations.
A successful agent explanation is not a release criterion.
A reproducible check against a protected requirement can be.
Overall it might bring 2 important things:
Behavioral correctness
What states and event sequences are allowed?
TLA+ helps reason about concurrency, retries, failures, safety and progress.
Structural discipline
What dependencies and responsibilities are allowed?
Import rules, schemas and static checks constrain architectural drift.
The process at a glance
It follows the stages in order, but loop back whenever evidence exposes a flaw. A failing design returns to architecture, a failing implementation returns to code. Changes to requirements need a separate review.
- Formal requirementsDone by human, expresses intent, properties and assumptions.
- Architecture search (Residuality)Stressors, residues and candidate designs.
- Design verificationCheck the chosen protocol and its failures.
- ImplementationCode within protected constraints.
- Model conformanceConnect the abstract model to real behavior.
- Conventional verificationTypes, tests, boundaries and security checks.
- Adversarial verificationFaults, hostile inputs and stressed execution.
- Controlled deploymentEvidence gate, canary and recovery path.
- Runtime verificationObserve properties and feed failures back.
The important loop:
Requirements → Architecture candidate → Refined formal model → Verification → Accepted design.
TLA+ belongs before implementation and after architectural changes.
Each step in practice
01 / Define the contractFormal requirements
Start with a small ticket/card/whatever: what should change, for whom, and what must remain true. Give properties stable identifiers so the same requirement can be traced through the model, tests and production.
- Safety: something bad never happens. Example: a command ID causes at most one committed mutation.
- Liveness: something good eventually happens. Example: an accepted command eventually receives an outcome, provided the server recovers and communication resumes.
- Assumptions: the conditions under which the claims hold, including durability, eventual connectivity and scheduling fairness.
- Structural rules: domain code cannot import "X package" or "Y package" adapters, handlers delegate business operations to application services.
Use TLA+ for states, transitions and temporal properties. Keep product intent and structural constraints alongside it. Not every ticket needs a new model: routine UI changes can reference existing contracts.
What I say ticket/card/whatever I actually mean a set of files (this step is hard and should be taken seriously):
feature/
requirements.md Human intent + property IDs
Feature.tla Behavioral specification
Feature.cfg Model-checker configuration
architecture-rules.* Executable dependency constraints
assumptions.md Scope, failures and trust boundaries02 / Explore resilienceArchitecture search
Use Residuality Theory, developed by Barry M. O'Reilly, as a way to challenge designs: expose a candidate architecture to stressors and examine the useful capabilities or structures that remain: the "residues". Compare candidates and document tradeoffs.
For example, for a WebSocket service, we could imagine some of the stressors being: duplicate commands after reconnect, database unavailability, a process crash after commit, delayed broadcasts, authorization revocation and traffic spikes. These must be random, do not use probability there, include combinations and failures outside the happy path. Check Residuality Theory to learn more about it.
A stressor/residue incidence matrix can organize the analysis. Its entries need defined meanings and evidence, a matrix calculated from guesses does not establish resilience.
Residuality generates and challenges architectures. It does not prove correctness.
Neither the number of stressors nor the presence of matrix calculations is a mathematical correctness certificate. Include complexity, operations and cost when selecting the design.
03 / Verify the designFormal design verification
Refine the behavioral model to include the selected architecture. An outbox, retry queue or separate broadcaster introduces states and failure windows that the initial requirements model may not contain.
Model persistence, acknowledgement, retries, crashes, recovery and synchronization. Ask whether the properties survive every behavior covered by the chosen verification method.
| Technique | What it establishes | Practical use |
|---|---|---|
| TLC | Explores reachable states of a configured model and checks selected properties. A complete finite run covers that model. | Start here: small protocols, explicit failures and counterexamples. |
| Apalache | Symbolic verification of TLA+ using solver-backed techniques. Bounded results have a stated bound, an inductiveness check answers a different proof obligation. | Use when the model suits symbolic checking, record exactly which mode and scope passed. |
| TLAPS | Mechanically checks supplied proof obligations about a formal specification. | Use selectively for important properties that justify proof effort. Check supported obligations, do not assume automatic proof of all temporal claims. |
Check that the model permits meaningful progress and that properties are not passing vacuously. A system that never acknowledges anything trivially satisfies “no ACK before commit.” Liveness needs explicit fairness and recovery assumptions.
A counterexample is a design review input. Fix the transitions or revise an incorrect assumption through review, do not relax the property merely to obtain a passing result.
04 / Build against the contractImplementation
The coding agent receives the approved specification, selected architecture, relevant source files and executable boundary rules. It implements the feature and maps important model actions to code paths.
Make constraints enforceable. For example, use dependency-cruiser, linter import restrictions or Nx module boundaries to prevent domain modules from depending on infrastructure. Typed languages and runtime schemas enforce complementary data contracts.
Instructions in AGENTS.md and ADRs provide context, CI rules enforce the parts that can be checked. Protect requirements, model properties, verification harnesses and release gates using permissions and independent review.
05 / Close the model-to-code gapModel-based conformance testing
A verified model does not verify the programming language implementation. This stage checks whether real executions correspond to behavior permitted by that model.
Build a harness that generates model actions, translates them into application operations, observes the result and compares abstract state. For example, Retry(cmd1) becomes a resend over a real connection, “processed once” becomes a query of committed effects in the test database.
- Model-based tests: generate operation sequences and compare them with a state-machine oracle.
- Property-based tests: vary payloads, commands and schedules, then shrink failures to a minimal reproducible case.
- Trace checking: map recorded events into model states and check legal transitions or named properties.
Define the abstraction carefully: internal implementation steps may correspond to stuttering in the model, and concurrent executions cannot always be compared using one naive total ordering. For objects that promise it, linearizability checking can compare concurrent histories with a sequential specification.
This bridge requires engineering. A TLA+ file does not automatically become a test oracle. The adapters, observation points and state mapping need validation. Passing generated tests supplies conformance evidence for exercised executions, not a proof of all possible program behaviors.
06 / Check the applicationConventional verification
Run the checks that catch implementation mistakes outside the abstract protocol: unit tests for business rules, integration tests for persistence and adapters, and E2E tests for actual user journeys.
Add type checking, runtime validation, dependency rules and relevant security analysis. Verify migrations and compatibility when the change affects stored data or older clients. Agents may write additional tests, but an independently reviewed oracle should define the expected result.
Loop implementation and tests until the checks pass. A changed expectation or deleted test is a contract change to review, not an ordinary fix.
07 / Challenge the executionAdversarial verification
Run the implementation under controlled faults: delayed database responses, disconnected clients, process termination, restart, resource pressure, malformed inputs and simultaneous retries.
For a more systematic approach, build deterministic simulation: replace clocks, scheduling, randomness and network delivery with controlled interfaces. Explore schedules and replay failing seeds. Real-service fault tests still matter because a simulator abstracts away deployment behavior.
Respect transport semantics. A live WebSocket over TCP provides ordered delivery on that connection. Model stale, duplicated or differently ordered application events where retries, reconnects, queues or multiple connections actually allow them, do not invent arbitrary frame reordering within one intact connection.
Evaluate the same properties used earlier, rather than merely checking that the process stayed alive. Bound recovery checks with a documented operational timeout, a finite timeout alone does not establish mathematical eventual progress.
08 / Release through an evidence gateControlled deployment
Ship only when the predefined checks for the feature's risk level pass. The gate verifies evidence attached to the exact release artifact, rather than accepting an agent's summary.
Use staged rollout or a canary where appropriate, define rollback triggers, and ensure recovery is compatible with data migrations. A rollback may require a forward fix or data repair, reverting a binary does not undo committed database changes.
Near-autonomous releases need narrow deployment permissions and a policy for when to stop. Requirements changes, destructive migrations or an unexplained failed invariant should route to human review according to that policy.
09 / Keep checking after releaseRuntime verification
Instrument the application with command IDs, commit outcomes, acknowledgements, versions and relevant authorization context. Monitor invariants alongside latency, error rates and availability objectives.
An investigation agent gathers evidence, correlates traces, reproduces failures and proposes patches. Those patches re-enter the same pipeline. Production write access and emergency actions follow an explicit operational policy.
Telemetry is evidence with limits. Missing or reordered log entries can create false alarms or hide failures. Cross-process timestamps alone do not prove causality. Use durable records and causal identifiers where possible, and report incomplete traces as inconclusive.
Specialized agents, separate authority
Split responsibilities so the implementation agent cannot define the requirements, change the oracle and approve its own release. These can be separate sessions or workers, the permission boundaries matter more than the number of agents.
| Role | Responsibility | Boundary |
|---|---|---|
| Specification agent | Translate human intent into candidate properties and assumptions. | Human or designated owner approves the contract. |
| Architecture agent | Challenge candidates using stressors and Residuality analysis. | Cannot redefine correctness to favor its design. |
| Verification agent | Check models, proof obligations and the relevance of assumptions. | Receives requirements independently, reports exact verification scope. |
| Implementation agent | Write code and resolve implementation failures. | Cannot weaken protected properties, oracles or release gates. |
| Conformance agent | Maintain adapters, mappings and model-based tests. | Expected behavior comes from the approved contract. |
| Adversarial agent | Generate faults, edge cases and difficult schedules. | Operates within isolated test environments and a defined budget. |
| Runtime audit agent | Investigate production violations and propose regressions or fixes. | Production mutation requires the configured operational authority. |
| CI / release gate | Evaluate required evidence and enforce release policy. | Approval is based on checks, not persuasive agent prose. |
Several agents using the same model can share blind spots. Role separation is not statistical independence and does not itself constitute proof. Deterministic checks, independent requirement review, protected files and varied verification techniques supply stronger boundaries.
One property, from model to production
Example: a client retries a WebSocket command after losing its acknowledgement. The database effect must occur at most once, and a success ACK must refer to a durable commit.
No duplicate effect
For each command identity, the number of committed business mutations is at most one.
No premature success
A success acknowledgement implies that the corresponding mutation and recoverable result are committed.
The failure the design must survive
- The client sends
cmd-42. - The server commits the mutation.
- The connection drops before the success ACK reaches the client.
- The client reconnects and retries
cmd-42. - The server returns the stored result without repeating the mutation.
A design that separately checks “already processed,” executes the mutation and then records the ID has a race and crash window. Two requests can both pass the check, a crash can happen after the effect but before recording completion.
For a database-only mutation, coordinate the command identity, business change and stored result in one database transaction, with an appropriate uniqueness constraint and concurrency handling. Include an outbox record in that transaction if a recoverable broadcast is required. External effects require their own idempotency or coordination strategy.
Receive command with a scoped, stable identity
Begin transaction
Claim identity under a uniqueness constraint
Apply business mutation
Store result and, if needed, outbox event
Commit transaction
Send success ACK
Deliver outbox event, clients tolerate retriesThe duplicate path returns the committed stored result, conflict handling must distinguish a completed command from an in-flight or failed one. Define how long identities remain valid, how payload mismatches are rejected, and how the identity is scoped to a caller or tenant.
| Layer | Evidence for P-01 and P-02 |
|---|---|
| TLA+ model | Model retry, concurrency, commit, crash and ACK transitions. Check at-most-once effects and ACK-implies-commit. |
| Conformance harness | Generate retries and failures, compare command outcomes and committed effects with abstract state. |
| Integration tests | Send concurrent duplicate IDs and interrupt the process around commit. Verify transaction behavior and replayed results. |
| Runtime verification | Correlate ACKs with durable command records and audit duplicate effects using command identity. |
This is an at-most-once effect claim within a defined scope, not an unconditional “exactly once delivery” promise. Eventual completion additionally requires progress and recovery assumptions.
How to use MCSEP in a real project
Start with one risky behavior in your existing application. A command → database mutation → ACK → reconnect/retry flow is for instance a good first slice for a classic web app.
- Write a one-page contract. Pick two safety properties, one progress property and explicit failure assumptions.
- Model a deliberately broken protocol. Let TLC find duplicate execution after a retry. Keep the counterexample as a learning artifact.
- Improve the design. Add durable command identity and model the transaction boundary. Challenge it with a small stressor analysis.
- Implement the narrow slice. Enforce module boundaries and protect the approved contract.
- Build one conformance adapter. Generate send, disconnect, reconnect and retry actions against a real test service.
- Add controlled faults and a release gate. Store reproducible results with the build, monitor the same property after release.
Scale assurance to risk
| Change | Reasonable initial evidence |
|---|---|
| Presentation or routine CRUD | Existing contracts, type and boundary checks, focused functional tests. |
| Retries, concurrency or distributed state | Scoped model checking, conformance tests and fault injection alongside ordinary checks. |
| Critical invariant or difficult protocol | Deeper models, proof obligations where justified, stronger review and validated implementation mapping. |
Set budgets for model state space, generated tests and agent retries. On budget exhaustion, record an incomplete result and escalate under the release policy, do not relabel it as a pass.
What should a release evidence record contain?
Requirement IDs and versions, model and configuration hashes, tool versions, stated assumptions, checker scope and results, proof results where applicable, implementation commit and artifact hash, abstraction mapping, test seeds and traces, structural checks, fault-test outcomes, approved exceptions, rollout and runtime thresholds.
What happens when a check fails?
A model counterexample returns to design. A mismatch against a sound model returns to implementation or the conformance adapter. An inadequate requirement returns to its owner for review. A production violation becomes a reproducible incident and regression case. Preserve the failing evidence before trying a fix.
Disclaimer: the assurance gaps
A mathematical proof establishes a claim about a formal system under stated assumptions. It does not automatically certify your deployed application.
| Boundary | What can go wrong | How to reduce the gap |
|---|---|---|
| Human intent → specification | The model precisely captures the wrong requirement or omits a necessary property. | Review concrete scenarios, assumptions, forbidden outcomes and vacuous properties. |
| Specification → architecture | The refined design introduces behavior absent from the requirements model. | Explicit mappings, refinement obligations and verification after design changes. |
| Architecture → implementation | The program violates a correct protocol or an adapter observes it incorrectly. | Conformance checks, independent oracles, static rules and implementation-level verification where feasible. |
| Source → compiler, runtime and libraries | Dependencies or execution semantics invalidate an assumption. | Record the trusted components, pin relevant versions and test real integrations. |
| Runtime → production environment | Storage, network, configuration or hardware behaves outside the model. | Fault testing, operational limits, staged rollout and runtime evidence. |
State the assurance claim narrowly: “Under assumptions A, property P was verified for model M using method V, implementation build B passed the following conformance and fault checks.”
TLC results are scoped to the configured model. Bounded symbolic checks are scoped to their bounds unless additional proof obligations establish more. TLAPS checks formal proofs, the connection to production code still needs evidence. Testing and monitoring observe executions rather than exhaust all possible behaviors.
For actual certification, identify the relevant standard and its requirements for evidence, tool qualification and independent assessment. MCSEP can organize supporting evidence, this page does not confer certification.
Sources and further reading
Primary sources and project resources for the techniques described here:
- Barry M. O'Reilly — Residuality Theory author and publication record
- An Introduction to Residuality Theory: Software Design Heuristics for Complex Systems — Procedia Computer Science 170 (2020), DOI 10.1016/j.procs.2020.03.120
- TLA+ — Leslie Lamport's introduction and resources
- TLA+ tools and TLC
- TLAPS — TLA+ Proof System
- Apalache — symbolic verification of TLA+
- fast-check — property-based and model-based testing for JavaScript and TypeScript
- dependency-cruiser — executable dependency rules