How OpenMAIC DSL Contract Enforcement Works at Runtime: A Technical Deep Dive
The OpenMAIC DSL contract is enforced at runtime through zero-dependency validator functions in the @openmaic/dsl package that check structural validity, version stamps, and timestamp formats before any data reaches storage.
The OpenMAIC framework defines a domain-specific language (DSL) for structuring educational content—stages, scenes, actions—and a separate runtime envelope for tracking learner sessions and records. This article explains exactly how the OpenMAIC DSL contract enforcement at runtime prevents invalid data from persisting, based on the source code in the THU-MAIC/OpenMAIC repository.
Document-Side Contract Validation
When a course is created, imported, or edited, structural validators ensure the DSL objects conform to the schema.
The core validation logic lives in packages/@openmaic/dsl/src/validate.ts. Functions like validateScene and validateAction walk the object graph, check required fields, verify discriminants, and return a ValidationResult object.
import { validateStage } from '@openmaic/dsl';
// Generated from PPTX import or manual authoring
const stage = await importPptx(fileBuffer);
const validation = validateStage(stage);
if (!validation.valid) {
console.error('Generated stage violates DSL:', validation.errors);
// Abort import before any persistence occurs
}
Key source locations:
validateScene— Lines 10-15 invalidate.tscheckAction— Lines 51-64 invalidate.ts
These validators run in-process with no external dependencies, making them suitable for Node.js, Deno, browsers, or test environments.
Runtime-Side Contract Validation
The runtime layer maintains its own envelope with stricter requirements. Every RuntimeSession and RuntimeRecord must carry:
- A version stamp (
runtimeDslVersion) distinct from document-sidedslVersion - Valid ISO-8601 timestamps for
createdAtandupdatedAt - Required identity fields (
id,learnerKey,stageId)
The validateRuntimeSession and validateRuntimeRecord functions enforce these rules:
import {
validateRuntimeSession,
RUNTIME_DSL_VERSION,
} from '@openmaic/dsl';
const session = {
id: 'sess-123',
kind: 'chat',
stageId: 'stage-42',
learnerKey: 'user-99',
status: 'active',
createdAt: '2026-09-06T12:00:00Z',
updatedAt: '2026-09-06T12:30:00Z',
runtimeDslVersion: RUNTIME_DSL_VERSION,
};
const result = validateRuntimeSession(session);
if (!result.valid) {
throw new Error(`Invalid session: ${result.errors.map(e => e.message).join('; ')}`);
}
Source: validateRuntimeSession (lines 53-84) and validateRuntimeRecord (lines 35-73) in validate.ts.
Version and Migration Guards
A critical defense mechanism prevents cross-line data corruption. The runtime contract uses runtimeDslVersion while documents use dslVersion. The runLadder helper in src/runtime.ts (lines 30-45) throws a hard error if these stamps appear on the wrong object type.
This prevents "lift-and-merge" accidents where legacy document data might be incorrectly treated as runtime session data, or vice versa. The validation block at lines 76-98 of validateRuntimeSession implements the stamp check explicitly.
Storage Layer Enforcement
All persistence operations invoke validators before writing. The HTTP-based store in packages/@openmaic/storage/src/runtime/http.ts demonstrates this pattern:
import { validateRuntimeRecord } from '@openmaic/dsl';
async function saveRecord(record) {
const { valid, errors } = validateRuntimeRecord(record);
if (!valid) {
// Returns HTTP 400 before touching the database
return { status: 400, body: { errors } };
}
// Proceed to persistence only after validation passes
}
Concrete call sites:
validateRuntimeSession(session)— Line 96 inhttp.tsvalidateRuntimeRecord(record)— Line 108 inhttp.ts
The PostgreSQL implementation (src/runtime/pg.ts) applies identical guards, ensuring consistent enforcement across storage backends.
Zero-Dependency Design Guarantees
The validators are implemented as pure TypeScript/JavaScript functions with no reliance on:
- Native
Dateparsing (ISO-8601 strings are validated character-by-character) - External schema libraries
- Runtime type systems
JSON Schema artifacts exist only for non-TypeScript consumers. This design ensures OpenMAIC DSL contract enforcement at runtime functions identically in any JavaScript environment without dependency bloat.
Summary
- Structural validation via
validateStage,validateScene,validateActioninvalidate.tsguards document-side DSL objects - Runtime envelope validation via
validateRuntimeSessionandvalidateRuntimeRecordensures sessions and records carry correct stamps and timestamps - Version separation between
dslVersionandruntimeDslVersionprevents accidental cross-line data merging - Storage-layer guards in HTTP and PostgreSQL implementations reject invalid payloads with 400-series errors before persistence
- Zero-dependency design enables universal runtime deployment without external requirements
Frequently Asked Questions
What happens if a runtime session has the wrong version stamp?
The validator throws a hard error during validateRuntimeSession execution. Lines 76-98 in validate.ts explicitly check that runtimeDslVersion is present and valid; if a document-side dslVersion appears instead, validation fails with a descriptive error message. The runLadder helper in runtime.ts provides additional cross-line guards.
Can I use the OpenMAIC validators outside of Node.js?
Yes. The @openmaic/dsl package has zero dependencies and uses only pure JavaScript/TypeScript. The validators run identically in browsers, Deno, serverless edge runtimes, and test harnesses without modification or additional packages.
Where does validation occur relative to database writes?
Validation occurs immediately before any persistence operation. In the HTTP storage implementation (http.ts), validateRuntimeSession is called at line 96 and validateRuntimeRecord at line 108—both returning 400-level responses if validation fails, preventing any database interaction with invalid data.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →