Constraint Visibility in Practice: A Multi-Module Case Study
SysMARA's core claim is Constraint Visibility: every business rule should be discoverable from the system's machine-readable artifacts, without reading source code or human-written documentation. This post is a case study proving that claim with a real multi-module system.
Everything below — every YAML snippet, every CLI output, every generated file — was captured from a live SysMARA v0.7.1 session. You can reproduce it in under 5 minutes.
The system: inventory + orders
We designed a minimal e-commerce backend with meaningful architectural constraints:
- 2 modules:
inventory(product catalog, stock) andorders(order placement, cancellation) - 2 entities:
product(6 fields) andorder(7 fields) - 5 capabilities:
add_product,update_stock,create_order,cancel_order,list_orders - 3 invariants: stock non-negativity, price positivity, order quantity minimum
- 1 policy: discontinued products cannot be ordered
- 1 flow: order placement with saga compensation
- 1 forbidden dependency:
inventorymust not import fromorders
This is small enough to fit in a blog post, but complex enough to demonstrate cross-module constraint enforcement — the exact scenario where "just write it in the README" breaks down.
Step 1: Define the modules
# system/modules.yaml
modules:
- name: inventory
description: Product catalog and stock management
entities:
- product
capabilities:
- add_product
- update_stock
allowedDependencies: []
forbiddenDependencies:
- orders
- name: orders
description: Order management and fulfillment
entities:
- order
capabilities:
- create_order
- cancel_order
- list_orders
allowedDependencies:
- inventory
forbiddenDependencies: []
The key line: forbiddenDependencies: [orders] on the inventory module. This is not a
comment or a convention — it is a formal constraint that SysMARA validates on every build.
Step 2: Define invariants as first-class specs
# system/invariants.yaml
invariants:
- name: stock_cannot_be_negative
description: Product stock must never go below zero after any operation
entity: product
rule: product.stock must be >= 0 after any update
severity: error
enforcement: runtime
- name: price_must_be_positive
description: Product price must be greater than zero
entity: product
rule: product.price must be > 0
severity: error
enforcement: runtime
- name: order_quantity_must_be_positive
description: Order quantity must be at least 1
entity: order
rule: order.quantity must be >= 1
severity: error
enforcement: runtime
Each invariant has a name, an entity it protects, a rule in
plain language, a severity, and an enforcement mode. These are not documentation —
they are structured nodes in the system graph that the compiler reads.
Step 3: Bind invariants to capabilities
The create_order capability declares which invariants it must enforce:
# system/capabilities.yaml (excerpt)
- name: create_order
module: orders
description: Create a new order for a product
entities: [order, product]
input:
- name: product_id
type: uuid
required: true
- name: quantity
type: number
required: true
output:
- name: order
type: order
required: true
policies:
- only_active_products_orderable
invariants:
- stock_cannot_be_negative
- order_quantity_must_be_positive
Notice: create_order lives in the orders module but references
stock_cannot_be_negative, which is defined on the product entity in the
inventory module. This is a cross-module invariant binding. In a
traditional codebase, this constraint would live in a different service's source code — invisible
to the orders team and invisible to AI agents.
Step 4: Build and verify
$ sysmara validate
════════════════════════════════════════════════════════════
Validation Results
════════════════════════════════════════════════════════════
Spec Type │ Count
──────────────┼───────
Entities │ 2
Capabilities │ 5
Policies │ 1
Invariants │ 3
Modules │ 2
Flows │ 1
[OK] Validation passed. 0 warning(s). $ sysmara build
Parsing specs...
[INFO] Found 2 entities, 5 capabilities, 1 policies, 3 invariants, 2 modules, 1 flows
Cross-validating...
[INFO] No cross-validation issues.
Building system graph...
[INFO] system-graph.json (14 nodes, 21 edges)
Compiling capabilities...
[INFO] Generated 15 file(s)
Scaffolding app/ stubs...
[INFO] Scaffold: 13 written, 0 skipped (already exist)
[OK] Build completed successfully. $ sysmara doctor
════════════════════════════════════════════════════════════
SysMARA Doctor — System Health Check
════════════════════════════════════════════════════════════
[PASS] Configuration: sysmara.config.yaml found
[PASS] Spec Directory: ./system directory found
[PASS] Spec Parsing: Parsed successfully: 2 entities, 5 capabilities,
1 policies, 3 invariants, 2 modules, 1 flows
[PASS] Cross-Validation: No cross-validation issues
[PASS] Module Boundaries: All boundaries valid
[PASS] Invariant Specs: All invariant specs valid
[PASS] Diagnostics: 0 error(s), 0 warning(s), 0 info
[PASS] Orphan Detection: No orphan specs detected
[PASS] Module Cycles: No dependency cycles detected
[OK] System is healthy. $ sysmara check boundaries
════════════════════════════════════════════════════════════
Boundary Check
════════════════════════════════════════════════════════════
[OK] All boundaries valid. No violations or cycles detected. 9 health checks pass. The system graph has 14 nodes and 21 edges — every entity, capability, policy, invariant, module, and flow is a node. Every relationship (uses_entity, governed_by, enforces, belongs_to) is a typed edge.
What AI agents actually see
When an AI agent is asked to implement create_order, it can query the system:
$ sysmara explain capability create_order
════════════════════════════════════════════════════════════
Capability: create_order
════════════════════════════════════════════════════════════
Description: Create a new order for a product
Module: orders
Entities
- order
- product
Input
- product_id: uuid (required)
- quantity: number (required)
Output
- order: order (required)
Policies
- only_active_products_orderable (effect: deny)
Invariants
- stock_cannot_be_negative [error]
- order_quantity_must_be_positive [error] This is Constraint Visibility. The AI does not need to:
- Read through 50 middleware files to find the product status check
- Grep for "stock" across the codebase to discover the non-negativity rule
- Ask a human "are there any business rules I should know about?"
- Hope that someone put it in the README
The constraints are declared on the capability, and the CLI returns them in a structured format that any LLM can parse.
The invariant explains itself
$ sysmara explain invariant stock_cannot_be_negative
════════════════════════════════════════════════════════════
Invariant: stock_cannot_be_negative
════════════════════════════════════════════════════════════
Description: Product stock must never go below zero after any operation
Entity: product
Rule: product.stock must be >= 0 after any update
Severity: error
Enforcement: runtime
Referenced by Capabilities
- update_stock (module: inventory)
- create_order (module: orders)
Two capabilities reference this invariant — one in inventory, one in orders.
The invariant itself does not "know" about modules. It is bound to the product entity.
Capabilities that touch product and declare this invariant get the enforcement wired in.
Impact analysis: what breaks if you change product?
$ sysmara impact capability create_order
════════════════════════════════════════════════════════════
Impact Analysis: capability:create_order
════════════════════════════════════════════════════════════
Affected Modules (2):
- inventory
- orders
Affected Capabilities (4):
- add_product
- cancel_order
- list_orders
- update_stock
Affected Invariants (3):
- order_quantity_must_be_positive
- price_must_be_positive
- stock_cannot_be_negative
Affected Policies (1):
- only_active_products_orderable
Affected Flows (1):
- order_placement_flow
Tests Likely Affected (5):
- tests/capabilities/add_product.test.ts
- tests/capabilities/cancel_order.test.ts
- tests/capabilities/create_order.test.ts
- tests/capabilities/list_orders.test.ts
- tests/capabilities/update_stock.test.ts
Generated Artifacts (14):
- generated/capability/add_product.ts ... (14 files)
Total Impact Radius: 11 nodes
Changing create_order affects 11 nodes across both modules. The impact analysis
tells the AI agent exactly which tests to run, which generated files will be regenerated, and
which invariants could be affected.
In a traditional codebase, this information does not exist in machine-readable form. A developer might know it intuitively. An AI agent cannot.
The flow: saga compensation across modules
# system/flows.yaml
flows:
- name: order_placement_flow
description: Place order, deduct stock, with compensation on failure
trigger: create_order
module: orders
steps:
- name: create_order
action: create_order
onFailure: compensate
compensation: cancel_order
- name: deduct_stock
action: update_stock
onFailure: compensate
compensation: update_stock $ sysmara flow validate order_placement_flow
════════════════════════════════════════════════════════════
Flow Validation: order_placement_flow
════════════════════════════════════════════════════════════
[OK] Flow is valid.
[INFO] Steps: 2
[INFO] Capabilities required: create_order, cancel_order, update_stock
The flow references capabilities from both modules. SysMARA validates that all referenced
capabilities exist and that the compensation actions are valid. If someone renames
cancel_order, the flow validation catches it at build time — not in production.
The generated code: constraints are structural
The scaffold for create_order — generated entirely from the YAML spec:
// SCAFFOLD: capability:create_order
// Edit Zone: editable — generated once, safe to modify
import { enforceOnlyActiveProductsOrderable }
from '../policies/only_active_products_orderable.js';
import { validateStockCannotBeNegative }
from '../invariants/stock_cannot_be_negative.js';
import { validateOrderQuantityMustBePositive }
from '../invariants/order_quantity_must_be_positive.js';
export async function handleCreateOrder(ctx) {
const input = ctx.body;
// Policy gate — present because spec declares it
if (!enforceOnlyActiveProductsOrderable(ctx.actor)) {
throw new Error('Policy violation: only_active_products_orderable');
}
const repo = orm.repository('order', 'create_order');
const result = await repo.create(input);
// Invariant checks — present because spec declares them
const stockViolation = validateStockCannotBeNegative(result);
if (stockViolation) throw new Error(stockViolation.message);
const qtyViolation = validateOrderQuantityMustBePositive(result);
if (qtyViolation) throw new Error(qtyViolation.message);
return result;
} Three observations:
-
The policy check (
enforceOnlyActiveProductsOrderable) is an import and a function call — generated becausepolicies: [only_active_products_orderable]appears in the capability spec. -
The invariant validators (
validateStockCannotBeNegative,validateOrderQuantityMustBePositive) are imported and called — generated becauseinvariants: [stock_cannot_be_negative, order_quantity_must_be_positive]appears in the capability spec. - The validator functions themselves are stubs — the developer (or AI agent) fills in the logic. But the call site is guaranteed. You cannot forget to call the validator.
The invariant validator: what the AI must fill in
// SCAFFOLD: invariant:stock_cannot_be_negative
// Edit Zone: editable — generated once, safe to modify
import type { Product } from '../entities/product.js';
export interface InvariantViolation {
invariant: string;
message: string;
severity: 'error' | 'warning';
}
export function validateStockCannotBeNegative(
entity: Product
): InvariantViolation | null {
// Rule: "product.stock must be >= 0 after any update"
// TODO: Implement your validation logic here.
return null;
} The AI agent sees:
- The invariant name
- The entity type it receives
- The rule in plain language
- The return type (structured violation or null)
Implementing if (entity.stock < 0) return violation is trivial. The hard part —
knowing this check exists and ensuring it is called — is already solved by the framework.
The system map: one file, full picture
// .framework/system-map.json (generated)
{
"modules": [
{
"name": "inventory",
"entities": ["product"],
"capabilities": ["add_product", "update_stock"],
"dependencies": []
},
{
"name": "orders",
"entities": ["order"],
"capabilities": ["cancel_order", "create_order", "list_orders"],
"dependencies": ["inventory"]
}
],
"capabilities": [
{
"name": "create_order",
"module": "orders",
"entities": ["order", "product"],
"policies": ["only_active_products_orderable"],
"invariants": [
"order_quantity_must_be_positive",
"stock_cannot_be_negative"
]
}
// ... 4 more capabilities
],
"entities": ["order", "product"],
"unresolved": []
} An AI agent can read this single JSON file and know:
- Which modules exist and their dependency graph
- Which capabilities each module exposes
- Which policies and invariants govern each capability
- Which entities are referenced across modules
- Whether anything is unresolved (dangling references)
Reproducing this case study
# Takes about 2 minutes
mkdir case-study && cd case-study
npx @sysmara/core init --db sqlite --orm sysmara-orm
# Copy the YAML specs from this post into system/*.yaml
# Then:
npx sysmara build
npx sysmara doctor
npx sysmara explain capability create_order
npx sysmara impact capability create_order
npx sysmara flow validate order_placement_flow
npx sysmara check boundaries
# Inspect generated code:
cat app/capabilities/create_order.ts
cat app/invariants/stock_cannot_be_negative.ts
cat .framework/system-map.json What this proves
This is not a theoretical argument. It is a working system you can build and query right now.
- Cross-module invariants work.
stock_cannot_be_negativeis defined onproduct(inventory) but enforced bycreate_order(orders). The binding is declared in the capability spec and compiled into the generated handler. - Module boundaries are formal. The system graph tracks allowed and forbidden
dependencies.
sysmara check boundariesvalidates them on every build. - Flows span modules safely. The
order_placement_flowcalls capabilities from bothordersandinventory, with compensation actions that SysMARA validates for existence and type-correctness. - Every constraint is queryable.
sysmara explainreturns the policies and invariants for any capability.sysmara impactreturns the blast radius of any change. No grep, no tribal knowledge, no hoping the docs are up to date.
Constraint Visibility is not a feature — it is the architecture. When every rule is a named node in a graph, AI agents can reason about the system the same way a senior engineer does: by knowing what they are not allowed to break.