Skip to content

Runtime semantics (3)

The three kinds that describe runtime behavior outside features themselves. Two of them carry Layer 2.

Engine-executable expression — typically a validation predicate.

{
"id": "rul_name_not_empty_a1b2",
"kind": "rule",
"name": "habit_name_not_empty",
"expression": "length(state.draftHabitName) > 0",
"errorMessage": "Habit name cannot be empty",
"behavior": {
"enforced_at": [
{ "kind": "ui_disabled", "ui_view": "ui_habits_screen_a1b2",
"binding": "submitButton" },
{ "kind": "pre_call", "feature": "feat_create_habit_h14a",
"on_failure": "abort" }
]
}
}

The expression is the rule’s predicate (RFC-002 syntax). The behavior.enforced_at array binds the rule to specific UI sites and call points. See RFC-002 — Rule expression grammar.

A screen — or, in v0.3, a multi-screen view tree.

{
"id": "ui_habits_screen_a1b2",
"kind": "ui_view",
"name": "Habits screen",
"viewType": "list",
"behavior": {
"rootScreen": "list",
"screens": {
"list": {
"sections": [
{ "kind": "heading", "level": 1, "text": "My habits" },
{ "kind": "list", "source": "state.habits",
"itemTemplate": [
{ "kind": "text", "body": "{{ item.name }}" }
] },
{ "kind": "button", "label": "Add habit",
"dispatch": "navigate_to_add", "variant": "primary" }
]
},
"add": {
"sections": [
{ "kind": "heading", "level": 2, "text": "New habit" },
{ "kind": "input", "name": "habitName", "bind": "state.draftHabitName" },
{ "kind": "button", "label": "Create",
"dispatch": "feat_create_habit_h14a", "variant": "primary" }
]
}
}
}
}

viewType is one of list / form / detail / dashboard / wizard / custom. It seeds Pattern C’s template selection when Layer 2 is empty.

Multi-screen views compile to a top-level $Switch keyed by a state slot. See Codegen → SenLang bridge.

External service descriptor — protocol, base URL, auth method.

{
"id": "int_habits_api_c3d4",
"kind": "integration",
"name": "Habits REST API",
"protocol": "http",
"baseUrl": "https://api.example.com",
"auth": "bearer"
}

protocol is one of http / webhook / sms / email / graphql / grpc / mcp / sse / websocket / database.

No Layer 2 — integrations are descriptive. Features bind to them via depends_on edges:

{
"type": "depends_on",
"from": "feat_load_habits_e5f6",
"to": "int_habits_api_c3d4"
}

The codegen bridge uses the integration to resolve relative endpoint URLs in feature.behavior.steps[*].endpoint.