Guides
Pinning to a schema
A contract and the service that calls it must agree on the names and types of the facts, and on the set of actions. Validation options make that agreement explicit: pass the schema the service implements, and validation refuses any contract that differs from it.
scripts/schema-check.tsexample project// Fail fast when the contract and the service disagree about facts or actions.
import { readFileSync } from 'node:fs';
import { compileSource, formatDiagnostic, type Primitive } from '../vendor/ulang-lite/src/index.ts';
const source = readFileSync(new URL('../policy/deploy.ul', import.meta.url), 'utf8');
// What the service actually sends and does. Keep this next to the code that builds the facts.
const SERVICE = {
entity: 'DeployRequest',
fields: new Map<string, Primitive>([
['environment', 'string'], ['tests_passed', 'bool'], ['approvals', 'int'],
['author_approved_own_change', 'bool'], ['error_rate_pct', 'float'], ['change_freeze', 'bool'],
]),
actions: new Set(['deploy', 'rollback']),
};
function check(label: string, schema: typeof SERVICE) {
const result = compileSource(source, schema);
console.log(`${label}: ${result.ok ? 'ok' : formatDiagnostic(result.diagnostic, 'policy/deploy.ul')}`);
}
check('service schema', SERVICE);
check('service adds a hotfix action', { ...SERVICE, actions: new Set([...SERVICE.actions, 'hotfix']) });
check('service renames approvals', {
...SERVICE,
fields: new Map([...SERVICE.fields].map(([name, type]) => [name === 'approvals' ? 'approval_count' : name, type] as [string, Primitive])),
});$ node scripts/schema-check.ts
service schema: ok
service adds a hotfix action: policy/deploy.ul:18:3: semantic[trigger-incomplete]: TRIGGER must list all actions for its contract
service renames approvals: policy/deploy.ul:5:5: semantic[fields]: CONTEXT must exactly match DeployRequest facts schema| Option | Fails with | When |
|---|---|---|
entity | semantic[entity] | the contract's entity has another name |
fields | semantic[fields] | the entity's fields or their types differ |
actions | semantic[trigger-entry], semantic[trigger-incomplete] | TRIGGER lists an action the service does not have, or misses one it does |
Run the check where the schema lives: in the service's tests, or at startup before serving. µLang Git checks every contract it loads this way.