{ "category": "Transactions / State / Concurrency", "check": { "population": "every multi-step write, shared mutable state and retried side effect", "freshness": "a verdict stands until the write path, the isolation level or the concurrency model changes", "refusal": "the transaction or concurrency test fails a write path that loses an update, commits partially or repeats an effect", "observation": "outcomes of concurrent and retried runs, plus the transaction boundaries read from source", "evidence": "none: the catalog states this check as a class, so a watched run belongs to each system that adopts it", "authority": "the transaction boundary and the isolation level, which every write path conforms to" }, "records": [ { "id": "idempotency", "name": "Idempotency", "aliases": ["Idempotence"], "definition": "A design rule that repeating an operation with the same input has the same effect as running it once.", "type": "principle", "scope": [ "API", "command", "message handler" ], "requires": ["Idempotency Key or Deterministic Operation"], "reinforces": [ "Retry Safety", "Event-Driven Architecture" ], "enables": ["Safe Retries"], "conflicts_with": ["Non-Repeatable Side Effects"], "tensions_with": ["State Tracking"], "violated_by": [ "lexicon:non-idempotent-operation", "lexicon:duplicate-side-effects" ], "detected_by": ["side-effectful handlers without deduplication"], "measured_by": ["duplicate-effect defect rate"], "refactored_by": [ "lexicon:idempotency-key", "architecture:idempotent-consumer" ], "enforced_by": [ "retry tests", "API policy" ], "severity": "mandatory", "exemplar": { "before": "app.post(\"/foo\", async request => fooStore.create(await request.json()));", "after": "app.post(\"/foo\", async request => {\n const key = requireHeader(request, \"Idempotency-Key\");\n const body = await request.json();\n return idempotency.execute(key, () => fooStore.create(body));\n});", "lang": "ts" } }, { "id": "atomicity", "name": "Atomicity", "definition": "A design rule that the steps of a state change either all take effect or none do.", "type": "principle", "scope": [ "transaction", "operation", "workflow" ], "requires": ["Transaction Boundary"], "reinforces": [ "Consistency", "Correctness" ], "enables": ["All-or-Nothing State Change"], "conflicts_with": ["Partial Commit"], "tensions_with": ["Distributed Scalability"], "violated_by": ["lexicon:partial-commit"], "detected_by": ["multi-step writes without transaction/compensation"], "measured_by": ["partial failure rate"], "refactored_by": [ "lexicon:introduce-transaction-boundary", "architecture:saga-pattern", "architecture:compensating-transaction" ], "enforced_by": ["transaction tests"], "severity": "mandatory", "exemplar": { "before": "await fooStore.remove(from, foo.id);\nawait fooStore.add(to, foo.id);", "after": "await database.transaction(async tx => {\n await tx.foos.remove(from, foo.id);\n await tx.foos.add(to, foo.id);\n});", "lang": "ts" } }, { "id": "acid", "distinctFrom": [ { "id": "lexicon:base-eventual-consistency", "reason": "ACID keeps each transaction atomic, consistent, isolated and durable, while BASE favors availability and lets replicas converge later." } ], "name": "ACID", "aliases": ["Atomicity, Consistency, Isolation, Durability"], "definition": "A conceptual representation of the four guarantees of a database transaction: atomicity, consistency, isolation and durability.", "type": "model", "scope": [ "database", "transaction" ], "requires": [ "Atomicity", "Consistency", "Isolation", "Durability" ], "reinforces": ["Correctness"], "enables": ["Strong Transactional Guarantees"], "conflicts_with": [], "tensions_with": [ "Distributed Availability", "BASE/Eventual Consistency" ], "violated_by": ["lexicon:partial-commit"], "detected_by": ["non-transactional multi-write invariants"], "measured_by": ["transactional invariant defects"], "refactored_by": [ "lexicon:introduce-transaction-boundary", "lexicon:invariant-check" ], "enforced_by": [ "DB transactions", "isolation tests" ], "severity": "contextual", "exemplar": { "before": "await fooDb.write(foo);\nawait barDb.write(bar);", "after": "await database.transaction({ isolation: \"serializable\" }, async tx => {\n await tx.foos.save(foo);\n await tx.bars.save(bar);\n assertInvariant(foo, bar);\n});", "lang": "ts" } }, { "id": "transaction-boundary", "distinctFrom": [ { "id": "lexicon:consistency-rules", "reason": "A transaction boundary fixes which writes one transaction covers, while consistency rules are the invariants it must keep inside that scope." } ], "name": "Transaction Boundary", "definition": "A rule or precondition that a transaction covers exactly the writes of one unit of work inside one service.", "type": "constraint", "scope": [ "unit of work", "aggregate", "service" ], "requires": ["Consistency Rules"], "reinforces": [ "Atomicity", "Unit of Work" ], "enables": ["Safe State Mutation"], "conflicts_with": ["Hidden Distributed Transaction"], "tensions_with": ["Large Transaction Scope"], "violated_by": ["lexicon:hidden-distributed-transaction"], "detected_by": ["transaction scope leakage"], "measured_by": ["transaction size/duration"], "refactored_by": [ "lexicon:restrict-exports", "architecture:saga-pattern" ], "enforced_by": ["transaction policy"], "severity": "mandatory", "exemplar": { "before": "await beginTransaction();\nawait controller.parse(request);\nawait service.validate(foo);\nawait repository.save(foo);\nawait commitTransaction();", "after": "async function createFoo(input: CreateFoo) {\n const foo = validateFoo(input);\n return database.transaction(tx => new FooRepository(tx).save(foo));\n}", "lang": "ts" } }, { "id": "unit-of-work-pattern", "name": "Unit of Work Pattern", "definition": "A design pattern that collects the changes of one use case and commits them together in a single transaction.", "type": "pattern", "aliases": ["Unit of Work"], "scope": [ "application service", "persistence" ], "requires": ["Transaction Boundary"], "reinforces": [ "Atomicity", "Consistency" ], "enables": ["Coordinated Persistence"], "conflicts_with": ["Scattered Save Calls"], "tensions_with": ["Repository Complexity"], "violated_by": ["lexicon:scattered-save-calls"], "detected_by": ["multiple independent saves in one use case"], "measured_by": ["save coordination defects"], "refactored_by": [], "enforced_by": ["persistence conventions"], "severity": "recommended", "exemplar": { "before": "await fooRepository.save(foo);\nawait barRepository.save(bar);\nawait eventRepository.save(event);", "after": "const uow = unitOfWork.begin();\nuow.foos.save(foo);\nuow.bars.save(bar);\nuow.events.append(event);\nawait uow.commit();", "lang": "ts" } }, { "id": "consistency", "distinctFrom": [ { "id": "architecture:correctness", "reason": "Consistency is stored data satisfying its invariants, while correctness is code behavior matching its specification." }, { "id": "architecture:fault-tolerance", "reason": "Consistency is data keeping its invariants, while fault tolerance is operation continuing through component failure." }, { "id": "architecture:interoperability", "reason": "Consistency is data inside one system keeping its invariants, while interoperability is separate systems exchanging data." }, { "id": "lexicon:always-fresh-reads", "reason": "Consistency is invariants holding after every change, while always-fresh reads is every read seeing the latest write." }, { "id": "lexicon:availability", "reason": "Consistency is data keeping its invariants, while availability is the system answering at all." }, { "id": "lexicon:durability", "reason": "Consistency is invariants holding after a change, while durability is a committed change surviving a crash." }, { "id": "lexicon:maintainability", "reason": "Consistency is a property of stored data, while maintainability is a property of the code that changes it." }, { "id": "architecture:scalability", "reason": "Consistency is invariants holding, while scalability is performance holding as load grows." }, { "id": "lexicon:operational-complexity", "reason": "Consistency is invariants holding, while operational complexity is the effort of running the system in production." }, { "id": "lexicon:quality", "reason": "Consistency is one property of stored data, while quality is how far a system meets all its expectations." }, { "id": "lexicon:security", "reason": "Consistency is data keeping its invariants, while security is protection from misuse and attack." }, { "id": "lexicon:simplicity", "reason": "Consistency is invariants holding, while simplicity is the absence of unneeded structure." } ], "name": "Consistency", "definition": "The degree to which stored data satisfies its invariants after every change.", "type": "quality-attribute", "scope": [ "data", "transaction", "distributed system" ], "requires": [ "Invariant", "Validation" ], "reinforces": ["Correctness"], "enables": ["Reliable State"], "conflicts_with": ["Inconsistent Replicas/Models"], "tensions_with": [ "Availability", "Latency" ], "violated_by": ["lexicon:reachable-invalid-state"], "detected_by": [ "data anomalies", "failed invariant checks" ], "measured_by": ["consistency violation count"], "refactored_by": [ "lexicon:invariant-check", "lexicon:introduce-transaction-boundary", "lexicon:reconciliation-job" ], "enforced_by": [ "database constraints", "invariant tests" ], "severity": "mandatory", "exemplar": { "before": "foo.total = foo.items.reduce((sum, item) => sum + item.value, 0);\nfoo.itemCount = externalCount;", "after": "function rebuildFoo(items: readonly FooItem[]): Foo {\n return { items, total: sum(items), itemCount: items.length };\n}\nconst foo = rebuildFoo(items);", "lang": "ts" } }, { "id": "isolation", "name": "Isolation", "definition": "A rule or precondition that concurrent transactions do not see each other's uncommitted changes, to the degree the isolation level declares.", "type": "constraint", "scope": [ "database", "transaction", "concurrency" ], "requires": ["Concurrency Control"], "reinforces": ["Correctness"], "enables": ["Safe Concurrent Operations"], "conflicts_with": ["Dirty Reads/Writes"], "tensions_with": ["Throughput"], "violated_by": ["lexicon:dirty-reads-writes"], "detected_by": [ "concurrency tests", "isolation anomalies" ], "measured_by": [ "anomaly rate", "lock contention" ], "refactored_by": [ "architecture:pessimistic-locking", "lexicon:transaction-isolation-level" ], "enforced_by": [ "DB isolation", "concurrency tests" ], "severity": "contextual", "exemplar": { "before": "const foo = await fooStore.find(id);\nfoo.count += 1;\nawait fooStore.save(foo);", "after": "await database.transaction({ isolation: \"serializable\" }, async tx => {\n const foo = await tx.foos.lock(id);\n await tx.foos.save({ ...foo, count: foo.count + 1 });\n});", "lang": "ts" } }, { "id": "concurrency-control", "name": "Concurrency Control", "definition": "A mechanism that coordinates concurrent access to shared state, through locks, versions or compare-and-swap.", "type": "mechanism", "scope": [ "transaction", "memory", "distributed system" ], "requires": ["Shared State Identification"], "reinforces": [ "Isolation", "Correctness" ], "enables": ["Safe Parallel Mutation"], "conflicts_with": [ "Race Conditions", "Lost Update" ], "tensions_with": ["Performance"], "violated_by": ["lexicon:race-conditions"], "detected_by": [ "race detectors", "flaky concurrent tests" ], "measured_by": [ "race count", "contention" ], "refactored_by": [ "architecture:pessimistic-locking", "lexicon:make-immutable", "architecture:optimistic-locking" ], "enforced_by": [ "thread-safety analysis", "tests" ], "severity": "mandatory", "exemplar": { "before": "const foo = await fooStore.find(id);\nawait fooStore.save({ ...foo, count: foo.count + 1 });", "after": "await fooStore.update(id, current => ({\n ...current,\n count: current.count + 1,\n}), { expectedVersion: foo.version });", "lang": "ts" } }, { "id": "optimistic-locking", "name": "Optimistic Locking", "aliases": ["Own-Span Compare-and-Swap"], "definition": "A design pattern that checks a record's version when it is written and rejects the write if another writer changed it first, comparing only the writer's own span where a surface is fenced per writer.", "type": "pattern", "scope": [ "persistence", "transaction" ], "requires": ["Version Field"], "reinforces": ["Concurrency Control"], "enables": ["Conflict Detection"], "conflicts_with": ["Blind Overwrite"], "tensions_with": ["Retry Complexity"], "violated_by": ["architecture:lost-update"], "detected_by": ["updates without version check"], "measured_by": ["conflict/retry rate"], "refactored_by": [], "enforced_by": [ "repository rules", "integration tests" ], "severity": "contextual", "exemplar": { "before": "await fooTable.update({ id: foo.id, name: foo.name });", "after": "const updated = await fooTable.update({\n id: foo.id,\n expectedVersion: foo.version,\n next: { ...foo, version: foo.version + 1 },\n});\nif (!updated) throw new ConflictError(foo.id);", "lang": "ts" } }, { "id": "pessimistic-locking", "name": "Pessimistic Locking", "definition": "A design pattern that locks a record before reading it for update, so other writers wait until the transaction ends.", "type": "pattern", "scope": [ "persistence", "critical section" ], "requires": ["Lock Ownership"], "reinforces": ["Isolation"], "enables": ["Strong Conflict Prevention"], "conflicts_with": [], "tensions_with": [ "Deadlocks", "Latency", "Lock-Free Throughput" ], "violated_by": ["lexicon:blind-overwrite"], "detected_by": ["concurrent update conflicts"], "measured_by": ["lock wait/deadlock rate"], "refactored_by": ["lexicon:apply-concurrency-control"], "enforced_by": ["transactional tests"], "severity": "contextual", "exemplar": { "before": "const foo = await fooTable.find(id);\nawait fooTable.save(change(foo));", "after": "await database.transaction(async tx => {\n const foo = await tx.foos.findForUpdate(id);\n await tx.foos.save(change(foo));\n});", "lang": "ts" } }, { "id": "state-isolation", "name": "State Isolation", "definition": "A design rule that each piece of mutable state belongs to one unit of concurrent execution, so no two units that run at the same time can write it.", "type": "principle", "scope": [ "function", "component", "service" ], "requires": [ "Encapsulation", "Ownership" ], "reinforces": [ "Predictability", "Concurrency Safety" ], "enables": ["Testability"], "conflicts_with": ["Shared Mutable State"], "tensions_with": ["Data Sharing"], "violated_by": ["lexicon:global-mutable-state"], "detected_by": [ "static mutable fields", "shared caches without ownership" ], "measured_by": ["global state count"], "refactored_by": [ "lexicon:encapsulate-state", "lexicon:pass-context-explicitly", "lexicon:make-immutable" ], "enforced_by": [ "lint rules", "architecture tests" ], "severity": "mandatory", "exemplar": { "before": "const globalFooState: Foo[] = [];\nfunction addFoo(foo: Foo) { globalFooState.push(foo); }", "after": "class FooSession {\n #state: Foo[] = [];\n add(foo: Foo) { this.#state = [...this.#state, foo]; }\n snapshot() { return [...this.#state]; }\n}", "lang": "ts" } }, { "id": "controlled-side-effects", "name": "Controlled Side Effects", "definition": "A design rule that mutation, I/O and persistence happen at declared boundaries, around a core of pure functions.", "type": "principle", "scope": [ "function", "module", "boundary" ], "requires": ["Effect Boundaries"], "reinforces": [ "Predictability", "Testability" ], "enables": ["Pure Core / Imperative Shell"], "conflicts_with": [ "Action at a Distance", "Hidden Side Effect" ], "tensions_with": ["Performance Optimization"], "violated_by": ["architecture:hidden-side-effect"], "detected_by": ["side effects in domain/pure functions"], "measured_by": ["side-effect boundary violations"], "refactored_by": [ "lexicon:make-effects-explicit", "lexicon:separate-query-from-command" ], "enforced_by": [ "effect linting", "layer rules" ], "severity": "recommended", "exemplar": { "before": "function calculateFoo(foo: Foo) {\n foo.count += 1;\n fooLog.record(foo);\n fooDb.save(foo);\n return foo.count;\n}", "after": "function nextFoo(foo: Foo): Foo { return { ...foo, count: foo.count + 1 }; }\nasync function applyFoo(foo: Foo, store: FooStore, log: Log) {\n const next = nextFoo(foo);\n log.write(next);\n await store.save(next);\n return next;\n}", "lang": "ts" } }, { "id": "petri-nets", "name": "Petri Nets", "definition": "A conceptual representation of concurrent flow as places holding tokens and transitions that consume and produce them, which can be analyzed for deadlock.", "type": "model", "scope": [ "concurrency", "workflow", "verification" ], "requires": ["Places and Transitions"], "reinforces": [ "Concurrency Correctness", "Deadlock Freedom" ], "enables": [ "Concurrent-Flow Modeling", "Reachability and Deadlock Analysis" ], "conflicts_with": ["Ad-Hoc Lock Ordering"], "tensions_with": ["Modeling Overhead"], "violated_by": ["lexicon:ad-hoc-lock-ordering"], "detected_by": ["deadlocks or lost tokens found only at runtime"], "measured_by": ["unreachable or deadlock-prone markings"], "refactored_by": [], "enforced_by": ["concurrency model review"], "severity": "contextual", "exemplar": { "before": "acquire(a); acquire(b); work(); release(b); release(a);", "after": "const net = petriNet({\n places: { idle: 1, aHeld: 0, bHeld: 0 },\n transitions: [\n { name: \"takeA\", consume: { idle: 1 }, produce: { aHeld: 1 } },\n { name: \"takeB\", consume: { aHeld: 1 }, produce: { bHeld: 1 } },\n ],\n});\nassertNoDeadlock(reachableMarkings(net));", "lang": "ts" } } ] }