{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$defs": {
    "AccessPermission": {
      "description": "Access permission level",
      "type": "string",
      "enum": [
        "read",
        "write",
        "read_write"
      ]
    },
    "Action": {
      "description": "Action defines an operation on an Entity or Service.\n",
      "type": "object",
      "properties": {
        "audit": {
          "type": "boolean"
        },
        "call": {
          "description": "sync (default) | async (§11.4)",
          "type": "string"
        },
        "callback": {
          "$ref": "#/$defs/CallbackDecl",
          "description": "§13.1: callback webhook delivery for tracked async jobs",
          "nullable": true
        },
        "challenge": {
          "description": "Challenge opts this action into its App's anonymous-intake",
          "type": "boolean"
        },
        "conditions": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ConditionDecl"
          }
        },
        "description": {
          "type": "string"
        },
        "disabled": {
          "description": "§11.1 — removes a standard action from every surface",
          "type": "boolean"
        },
        "emits": {
          "description": "event name linked per §12",
          "type": "string"
        },
        "expose": {
          "description": "per-action protocol filter: rest | grpc | ws",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "idempotency_key": {
          "$ref": "#/$defs/IdempotencyDecl",
          "nullable": true
        },
        "idempotent": {
          "type": "boolean"
        },
        "impl": {
          "$ref": "#/$defs/ImplDecl",
          "nullable": true
        },
        "name": {
          "type": "string"
        },
        "params": {
          "$ref": "#/$defs/ParamsDecl",
          "nullable": true
        },
        "public": {
          "description": "Public makes a SERVICE action callable by anonymous callers on the UI",
          "type": "boolean"
        },
        "rate_limit": {
          "$ref": "#/$defs/RateLimitSpec",
          "description": "1.4.1 per-action override (02-core-extended.md §17)",
          "nullable": true
        },
        "required_permission": {
          "description": "RequiredPermission is the permission a caller must hold. For a Service",
          "type": "string"
        },
        "track": {
          "description": "§13: call:async + track:true = tracked async job (job_id + progress)",
          "type": "boolean"
        },
        "ui": {
          "$ref": "#/$defs/ActionUIHint",
          "description": "Backend §5.1 — button rendering hints (confirm, icon, style, etc.)",
          "nullable": true
        },
        "uses": {
          "$ref": "#/$defs/UsesDecl",
          "nullable": true
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "ActionUIHint": {
      "description": "ActionUIHint carries frontend rendering hints for an action button (Backend §5.1).\n",
      "type": "object",
      "properties": {
        "button_label": {
          "type": "string"
        },
        "confirm": {
          "type": "string"
        },
        "icon": {
          "type": "string"
        },
        "show_when": {
          "description": "FormSpecExpr — condition to show this action button",
          "type": "string"
        },
        "style": {
          "description": "Button style variant",
          "type": "string",
          "enum": [
            "primary",
            "secondary",
            "danger"
          ]
        }
      },
      "additionalProperties": false
    },
    "AiIndexDecl": {
      "description": "AiIndexDecl is the optional AI discovery index on a Module\n(ai/04-formspec-remote-mcp.md §3). skills_for_ai is untrusted third-party input.\n",
      "type": "object",
      "properties": {
        "aliases": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "category": {
          "type": "string"
        },
        "features": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "integration_pattern": {
          "type": "string"
        },
        "skills_for_ai": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ApiGRPCConfig": {
      "description": "ApiGRPCConfig configures the gRPC external surface.\n",
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "package": {
          "type": "string"
        }
      },
      "required": [
        "enabled"
      ],
      "additionalProperties": false
    },
    "ApiRESTConfig": {
      "description": "ApiRESTConfig configures the REST external surface.\n",
      "type": "object",
      "properties": {
        "base_path": {
          "description": "@schema {example: \"/invoices\"}",
          "type": "string",
          "examples": [
            "/invoices"
          ]
        },
        "disable": {
          "description": "entities to opt-out",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "version": {
          "description": "@schema {example: \"v2\"}",
          "type": "string",
          "examples": [
            "v2"
          ]
        }
      },
      "additionalProperties": false
    },
    "AppAccess": {
      "description": "AppAccess controls whether an App's surface is publicly reachable without\nauthentication (frontend/05-app-kinds.md §1). `private` is the\nsecure-by-default. Orthogonal to the App renderer archetype: any of\nsidebar-nav/topnav/no-nav may be public or private.\n",
      "type": "string",
      "enum": [
        "private",
        "public"
      ]
    },
    "AppAuth": {
      "description": "AppAuth overrides the auth screens and chrome auth area for one App\n(plan docs_internal/plan/auth-screens-spec-driven.md). Each page slot is a\n`kind: Page` reference in `module/name` form; empty slots fall back to the\nframework's default auth page specs (module formspec.core). ChromeAuth is a\ncomponent asset reference replacing the default auth area (Sign in/Sign up/\nlogout/user menu).\n",
      "type": "object",
      "properties": {
        "change_password_page": {
          "description": "kind: Page ref (module/name) used for change-password — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/change-password"
          ]
        },
        "chrome_auth": {
          "description": "Component asset ref replacing the default chrome auth area — empty = default AuthArea driven by chrome.auth",
          "type": "string",
          "examples": [
            "portal/components/auth-area"
          ]
        },
        "login_page": {
          "description": "kind: Page ref (module/name) used as the login screen — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/login"
          ]
        },
        "oauth_callback_page": {
          "description": "kind: Page ref (module/name) used for the OAuth callback — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/oauth-callback"
          ]
        },
        "reset_password_page": {
          "description": "kind: Page ref (module/name) used for reset-password — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/reset-password"
          ]
        },
        "setup_page": {
          "description": "kind: Page ref (module/name) used as the first-run setup wizard — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/setup"
          ]
        }
      },
      "additionalProperties": false
    },
    "AppChrome": {
      "description": "AppChrome fine-tunes which chrome elements the App shell renders\n(frontend/05-app-kinds.md §4.1). Orthogonal to AppRenderer (layout\narchetype) and Access (auth axis): every element defaults to \"auto\" —\nthe archetype's own default — and explicit values override it. The meta\nAPI resolves the effective composition (internal/ui resolveChrome) so\nrenderers read final values.\n",
      "type": "object",
      "properties": {
        "auth": {
          "description": "Auth controls. \"links\": Sign in link + Sign up button (anon) /",
          "type": "string",
          "enum": [
            "auto",
            "links",
            "button",
            "none"
          ],
          "examples": [
            "auto"
          ]
        },
        "brand": {
          "description": "Brand bar — App title + logo.",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        },
        "breadcrumbs": {
          "description": "Breadcrumb row (sidebar-nav/topnav).",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        },
        "footer": {
          "description": "Page footer.",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        },
        "nav": {
          "description": "Navigation links derived from the resolved App menu.",
          "type": "string",
          "enum": [
            "auto",
            "menu",
            "none"
          ],
          "examples": [
            "auto"
          ]
        },
        "profile_route": {
          "description": "ProfileRoute is the in-app route to the signed-in user's profile",
          "type": "string"
        },
        "regions": {
          "description": "Chrome regions — topbar/sidebar/rightbar/bottombar/footer → none | auto | \u003ccomponent-ref\u003e",
          "type": "object",
          "additionalProperties": {},
          "examples": [
            "sidebar: auto"
          ]
        },
        "theme_switcher": {
          "description": "Theme switcher control (sidebar-nav/topnav).",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        }
      },
      "additionalProperties": false
    },
    "AppConfirm": {
      "description": "AppConfirm is the App-wide default confirm-dialog configuration\n(plan confirm-dialogs.md). Each verb holds the dialog message; nil =\ninherit/off, \"\" = explicitly off (opt out of an inherited default).\n",
      "type": "object",
      "properties": {
        "create": {
          "description": "Confirm message before create — absent = off; {name} interpolates the entity display name",
          "type": "string",
          "examples": [
            "Buat data baru?"
          ],
          "nullable": true
        },
        "delete": {
          "description": "Confirm message before delete — absent = off; {name} interpolates the entity display name",
          "type": "string",
          "examples": [
            "Hapus data ini?"
          ],
          "nullable": true
        },
        "update": {
          "description": "Confirm message before update — absent = off; {name} interpolates the entity display name",
          "type": "string",
          "examples": [
            "Simpan perubahan?"
          ],
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "AppConsume": {
      "description": "AppConsume is one cross-app interface an App depends on; it triggers a\ngrant request to the owning App (02-workspace-app-module.md §3).\n",
      "type": "object",
      "properties": {
        "actions": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "app": {
          "type": "string"
        },
        "service": {
          "type": "string"
        }
      },
      "required": [
        "app",
        "service"
      ],
      "additionalProperties": false
    },
    "AppInterface": {
      "description": "AppInterface is one cross-app service interface offered by an App\n(02-workspace-app-module.md §3).\n",
      "type": "object",
      "properties": {
        "actions": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "service": {
          "type": "string"
        }
      },
      "required": [
        "service"
      ],
      "additionalProperties": false
    },
    "ApprovalReject": {
      "description": "ApprovalReject declares the target state when the workflow is rejected.\n",
      "type": "object",
      "properties": {
        "to": {
          "type": "string"
        }
      },
      "required": [
        "to"
      ],
      "additionalProperties": false
    },
    "ApprovalSpec": {
      "description": "ApprovalSpec declares the approval gate on a state-machine transition\n(02-core-extended.md §2). It replaces the former `kind: Workflow` manifest:\nthe gate lives ON the transition it intercepts, so the declaration cannot\ndrift from the thing it gates, and a transition with several origin states is\ncovered by construction rather than by a reference kept in step by hand.\n\nIt is declared as `state_machine.transitions[].approval`.\n",
      "type": "object",
      "properties": {
        "on_reject": {
          "$ref": "#/$defs/ApprovalReject",
          "description": "OnReject declares the state the record moves to when the chain is",
          "nullable": true
        },
        "steps": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ApprovalStep"
          }
        }
      },
      "additionalProperties": false
    },
    "ApprovalStep": {
      "description": "ApprovalStep is one approval step in the approval chain.\nSteps are evaluated sequentially; each must reach quorum before the next begins.\n",
      "type": "object",
      "properties": {
        "approvers": {
          "description": "quorum, default 1",
          "type": "integer"
        },
        "description": {
          "description": "Description explains what to check before deciding (S15).",
          "type": "string"
        },
        "display_fields": {
          "description": "DisplayFields names the record fields the approver needs to see to decide",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "escalation": {
          "$ref": "#/$defs/StepEscalation",
          "nullable": true
        },
        "mode": {
          "$ref": "#/$defs/ApprovalStepMode",
          "description": "all | any | sequential"
        },
        "name": {
          "description": "Name identifies the step, so state about a workflow in flight can point at",
          "type": "string",
          "examples": [
            "supervisor-check"
          ],
          "pattern": "^[a-z][a-z0-9-]*$"
        },
        "permission": {
          "description": "Permission is the DUTY this step requires — the `resource + action` form",
          "type": "string",
          "examples": [
            "approve-void"
          ]
        },
        "roles": {
          "description": "Roles lists the roles eligible to sign — who, by NAME.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[gl.supervisor]"
          ]
        },
        "title": {
          "description": "Title is the human label for this approval task (S15). Without it the",
          "type": "string"
        },
        "when": {
          "description": "FormSpecExpr — skip step if false",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ApprovalStepMode": {
      "title": "Workflow Step Mode",
      "description": "How a step's quorum is collected. Closed set. `all` is refused at validate — use `any` with `approvers: N`, or `sequential`.",
      "type": "string",
      "enum": [
        "all",
        "any",
        "sequential"
      ]
    },
    "AssignmentDecl": {
      "description": "AssignmentDecl declares that an entity records a principal→dimension mapping\n(S5): a row of this entity links the principal identified by `PrincipalField`\nto the dimension value held in `Field`. The server resolves `from: session`\nrow-scope attributes from these declarations.\n",
      "type": "object",
      "properties": {
        "dimension": {
          "description": "Scope dimension this assignment provides a value for",
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "field": {
          "description": "Field on this entity holding the dimension value",
          "type": "string"
        },
        "principal_field": {
          "description": "Field on this entity identifying the principal; matched against the authenticated username",
          "type": "string",
          "examples": [
            "username"
          ]
        }
      },
      "required": [
        "dimension",
        "field",
        "principal_field"
      ],
      "additionalProperties": false
    },
    "AuthSettings": {
      "description": "AuthSettings configures external authentication (OAuth/OIDC) providers\n(auth redesign Fase 5). Providers are declared by name under\n`settings.auth.providers`; well-known presets (google, github, microsoft)\nfill in the endpoint URLs, custom providers declare them explicitly.\n",
      "type": "object",
      "properties": {
        "providers": {
          "description": "Providers maps a provider name → its OAuth config. The name is used in",
          "type": "object",
          "additionalProperties": {}
        }
      },
      "additionalProperties": false
    },
    "AutoFillDecl": {
      "description": "AutoFillDecl defines a client-side lookup/auto-fill on a field.\nWhen the relation field named in `from` (same child row) changes, the\nrelated record is fetched and its `field` value is copied into the field\nthat declares this AutoFillDecl.\n",
      "type": "object",
      "properties": {
        "field": {
          "description": "Field — name of the field on the related entity to copy from.",
          "type": "string"
        },
        "from": {
          "description": "From — name of the relation field in the same row that triggers the fill.",
          "type": "string"
        }
      },
      "required": [
        "from",
        "field"
      ],
      "additionalProperties": false
    },
    "BackdatePolicy": {
      "description": "BackdatePolicy controls how far back a transaction_date can be set (§14a).\n",
      "type": "object",
      "properties": {
        "max_days_back": {
          "type": "integer"
        },
        "override_permission": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "BlockBinds": {
      "description": "BlockBinds ties a detail block to the master list block that drives it in a\n`layout.mode: split` page (frontend/06-page-kinds.md §1.1).\n",
      "type": "object",
      "properties": {
        "param": {
          "description": "Param is the field of the selected master record injected into the",
          "type": "string"
        },
        "source": {
          "description": "Source is the `ref` of the master Table block whose row selection",
          "type": "string"
        }
      },
      "required": [
        "source",
        "param"
      ],
      "additionalProperties": false
    },
    "BlockRef": {
      "description": "BlockRef references another resource within a page block.\nEntity is resolved from the referenced Form/Table manifest's `spec.entity` —\nnot declared inline here (removed as redundant, since every Form/Table has\na 1:1 mapping to an entity).\n",
      "type": "object",
      "properties": {
        "asset": {
          "description": "component blocks (§7)",
          "type": "string"
        },
        "binds": {
          "$ref": "#/$defs/BlockBinds",
          "description": "Binds links a detail block to a master list block in a split layout",
          "nullable": true
        },
        "id": {
          "type": "string"
        },
        "mode": {
          "description": "view | edit",
          "type": "string"
        },
        "param": {
          "type": "object",
          "additionalProperties": {}
        },
        "props": {
          "description": "component blocks",
          "type": "object",
          "additionalProperties": {}
        },
        "ref": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "CacheSpec": {
      "description": "CacheSpec configures the framework read-through cache for find-by-id\n(Fase 14). TTL must parse as a Go duration (\"300s\", \"5m\") within 1s–1h.\n",
      "type": "object",
      "properties": {
        "ttl": {
          "description": "@schema {example: \"300s\"}",
          "type": "string",
          "examples": [
            "300s"
          ]
        }
      },
      "required": [
        "ttl"
      ],
      "additionalProperties": false
    },
    "CallbackDecl": {
      "description": "CallbackDecl configures callback webhook delivery for a tracked async job\n(02-core-extended.md §13.1, todo 7.13.4). The callback URL is supplied by\nthe caller via a request header; the result is delivered HMAC-signed.\n",
      "type": "object",
      "properties": {
        "channel": {
          "description": "webhook",
          "type": "string"
        },
        "header": {
          "description": "header carrying the callback URL (e.g. X-Callback-URL)",
          "type": "string"
        },
        "retry": {
          "$ref": "#/$defs/RetryDecl",
          "nullable": true
        },
        "sign": {
          "type": "boolean"
        },
        "url_from": {
          "description": "header",
          "type": "string"
        }
      },
      "required": [
        "channel"
      ],
      "additionalProperties": false
    },
    "Characteristic": {
      "title": "Characteristic",
      "description": "Data nature classification — determines storage strategy, partitioning, and API behavior",
      "type": "string",
      "enum": [
        "master",
        "transaction",
        "reference",
        "summary"
      ],
      "examples": [
        "transaction"
      ]
    },
    "ChildDecl": {
      "description": "ChildDecl defines a child relationship.\n",
      "type": "object",
      "properties": {
        "entity": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Field"
          }
        },
        "picker": {
          "$ref": "#/$defs/PickerDecl",
          "description": "Picker fills this child field by choosing records from another entity",
          "nullable": true
        },
        "sequence_field": {
          "type": "string"
        },
        "storage": {
          "description": "\"jsonb\" or \"table\"",
          "type": "string"
        }
      },
      "required": [
        "storage"
      ],
      "additionalProperties": false
    },
    "ComputedDecl": {
      "description": "ComputedDecl defines a computed/derived field.\n",
      "type": "object",
      "properties": {
        "formula": {
          "type": "string"
        }
      },
      "required": [
        "formula"
      ],
      "additionalProperties": false
    },
    "ConditionDecl": {
      "description": "ConditionDecl is a guard condition for an action (§13 level 3).\nThe canonical manifest form is {script, message}; {field, expression}\nis an older equivalent kept for backward compatibility.\n",
      "type": "object",
      "properties": {
        "expression": {
          "type": "string"
        },
        "field": {
          "type": "string"
        },
        "message": {
          "type": "string"
        },
        "script": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ConfigKey": {
      "description": "ConfigKey declares one configuration entry (01-core-basic.md §10).\n",
      "type": "object",
      "properties": {
        "default": {},
        "public": {
          "description": "Public opts the key in to UI-surface exposure (plan",
          "type": "boolean"
        },
        "secret": {
          "type": "boolean"
        },
        "type": {
          "description": "int | string | bool | decimal | json",
          "type": "string"
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "ContextDecl": {
      "description": "ContextDecl declares one render-context variable injected into a Page/Form\n(render-context-standard plan). Sources are a closed set:\n\n\tsession | entity | api | const | expr\n\nStandard slots (`user`, `route`, `fields`) are always present and need no\ndeclaration; `context:` adds named variables resolved from these sources.\n",
      "type": "object",
      "properties": {
        "call": {
          "description": "Call for source: api — \"module.service.action\".",
          "type": "string"
        },
        "config": {
          "description": "Config for source: config — \"\u003cconfig-name\u003e.\u003ckey\u003e\" referencing a",
          "type": "string"
        },
        "entity": {
          "description": "Entity ref for source: entity (\"module.entity\").",
          "type": "string"
        },
        "expr": {
          "description": "Expr for source: expr — a FormSpecExpr string evaluated against the",
          "type": "string"
        },
        "fallback": {
          "description": "Fallback is used while the source is loading or on error."
        },
        "id": {
          "description": "ID for source: entity — a record id, or a template token like",
          "type": "string"
        },
        "name": {
          "description": "Name is the context variable name (e.g. \"vendor\") — referenced in",
          "type": "string"
        },
        "params": {
          "description": "Params for source: api — action params.",
          "type": "object",
          "additionalProperties": {}
        },
        "realtime": {
          "description": "Realtime (source: entity) — subscribe to the entity's events and",
          "type": "boolean"
        },
        "source": {
          "description": "Context source — closed set.",
          "type": "string",
          "enum": [
            "session",
            "entity",
            "api",
            "const",
            "expr"
          ]
        },
        "value": {
          "description": "Value for source: const — a literal value."
        }
      },
      "required": [
        "name",
        "source"
      ],
      "additionalProperties": false
    },
    "CreateScopeSpec": {
      "description": "CreateScopeSpec pins a dimension field on CREATE from a record the payload\nreferences — the write-side counterpart of `row_scope`.\n\n`row_scope` answers \"which rows may this caller READ\". It cannot answer the\nwrite question, because a row that does not exist yet has no stored value to\nfilter: `create` is not row-scoped anywhere in the storage layer (InsertParams\ncarries no predicates). So the only place to state \"the branch of a new order\nis the branch of the table session it belongs to\" is the create path itself.\n\nThe rule is CONDITIONAL on the reference: when the payload carries a value for\nRefField, the dimension field must equal the referenced record's ViaField.\nWhen it does not (a cashier creating a walk-in order with no table session),\nthere is nothing to derive from and the rule does not apply — which is\ndeliberate, so one declaration serves both surfaces without a mode switch.\n\nA MISMATCH IS REJECTED (403), never silently overwritten. Overwriting would\nmake the payload lie about what was stored, and the caller would have no way\nto learn that their input was discarded.\n",
      "type": "object",
      "properties": {
        "field": {
          "description": "Dimension field on THIS entity that the create must pin",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        },
        "from": {
          "description": "Where the expected value comes from at request time. Only `record` is defined: a record the payload references.",
          "type": "string",
          "enum": [
            "record"
          ]
        },
        "ref_field": {
          "description": "Relation field on this entity holding the reference (id or natural key) to the record to read from",
          "type": "string",
          "examples": [
            "table_session_id"
          ]
        },
        "via": {
          "description": "The referenced record's entity, as \\\"\u003cmodule\u003e.\u003centity\u003e\\",
          "type": "string",
          "examples": [
            "cafe-order.table-session"
          ]
        },
        "via_field": {
          "description": "Field on `via` holding the expected value",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        }
      },
      "required": [
        "field",
        "ref_field",
        "via",
        "via_field"
      ],
      "additionalProperties": false
    },
    "CurrencySettings": {
      "description": "CurrencySettings configures the default money currency (05-field-types.md §2).\n",
      "type": "object",
      "properties": {
        "code": {
          "description": "Code is the ISO-4217 currency code (e.g. \"IDR\", \"USD\").",
          "type": "string"
        },
        "decimal_places": {
          "description": "DecimalPlaces is the minor-unit scale of this currency (e.g. IDR=0, USD=2).",
          "type": "integer",
          "nullable": true
        },
        "symbol": {
          "description": "Symbol is the optional display symbol (e.g. \"Rp\", \"$\"). When empty, the",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "DashboardWidget": {
      "description": "DashboardWidget places a widget on a dashboard.\n",
      "type": "object",
      "properties": {
        "config": {
          "type": "object",
          "additionalProperties": {}
        },
        "layout": {
          "$ref": "#/$defs/WidgetLayout"
        },
        "ref": {
          "type": "string"
        }
      },
      "required": [
        "ref",
        "layout"
      ],
      "additionalProperties": false
    },
    "DatastoreAccess": {
      "description": "DatastoreAccess controls who can use this datastore and what they can do.\n",
      "type": "object",
      "properties": {
        "filter": {
          "$ref": "#/$defs/DatastoreAccessFilter",
          "description": "Filter determines which workspaces can access this datastore.",
          "nullable": true
        },
        "permission": {
          "$ref": "#/$defs/DatastorePermission",
          "description": "Permission is the ceiling for operations on this datastore.",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "DatastoreAccessFilter": {
      "description": "DatastoreAccessFilter restricts datastore access to specific workspaces.\nAll fields are optional and combined with AND logic.\n",
      "type": "object",
      "properties": {
        "environment": {
          "description": "Environment restricts to workspaces in the named environment (e.g. \"production\").",
          "type": "string"
        },
        "labels": {
          "description": "Labels restricts to workspaces with all the given labels.",
          "type": "object",
          "additionalProperties": {}
        },
        "workspaces": {
          "description": "Workspaces restricts to a specific list of workspace IDs.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "DatastoreConnection": {
      "description": "DatastoreConnection holds the connection parameters.\n",
      "type": "object",
      "properties": {
        "database": {
          "type": "string"
        },
        "extra": {
          "type": "object",
          "additionalProperties": {}
        },
        "host": {
          "type": "string"
        },
        "lazy": {
          "description": "connect on first use",
          "type": "boolean"
        },
        "pool": {
          "$ref": "#/$defs/DatastorePool",
          "nullable": true
        },
        "port": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "DatastoreDriver": {
      "description": "Backend database/driver technology",
      "type": "string",
      "enum": [
        "sqlite",
        "postgres",
        "valkey",
        "redis",
        "s3",
        "garage",
        "minio",
        "nats",
        "memory",
        "fs"
      ]
    },
    "DatastorePermission": {
      "description": "DatastorePermission defines the operation ceiling for this datastore.\n",
      "type": "object",
      "properties": {
        "default": {
          "$ref": "#/$defs/AccessPermission",
          "description": "Default is the baseline access level. Default: read_write."
        },
        "rules": {
          "description": "Rules provide granular overrides for specific scopes.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/DatastorePermissionRule"
          }
        }
      },
      "additionalProperties": false
    },
    "DatastorePermissionRule": {
      "description": "DatastorePermissionRule overrides the default permission for a scope.\n",
      "type": "object",
      "properties": {
        "access": {
          "$ref": "#/$defs/AccessPermission",
          "description": "Access is the permission level for this scope."
        },
        "scope": {
          "description": "Scope is a glob pattern, e.g. \"store.*\", \"billing.invoice\", \"*.*\".",
          "type": "string"
        }
      },
      "required": [
        "scope",
        "access"
      ],
      "additionalProperties": false
    },
    "DatastorePool": {
      "description": "DatastorePool configures connection pooling.\n",
      "type": "object",
      "properties": {
        "max_idle": {
          "type": "integer"
        },
        "max_lifetime": {
          "description": "e.g. \"1h\", \"30m\"",
          "type": "string"
        },
        "max_open": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "DeliveryDecl": {
      "description": "DeliveryDecl configures what happens when an event fires.\n\nDeprecated: predates the nested event `deliver:` list (Core §12); kept for\nbackward compatibility with manifests using a top-level `deliver:` block.\n",
      "type": "object",
      "properties": {
        "channel": {
          "type": "string"
        },
        "event": {
          "type": "string"
        },
        "reliable_event": {
          "type": "boolean"
        },
        "websocket": {
          "type": "boolean"
        }
      },
      "required": [
        "event"
      ],
      "additionalProperties": false
    },
    "DeliveryTarget": {
      "description": "DeliveryTarget addresses the receiver of an event delivery.\n",
      "type": "object",
      "properties": {
        "action": {
          "type": "string"
        },
        "resource": {
          "description": "reliable_event: \"module.entity\"",
          "type": "string"
        },
        "scope": {
          "description": "websocket: workspace | user | ...",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "Dependency": {
      "description": "Dependency declares a module dependency.\n",
      "type": "object",
      "properties": {
        "module": {
          "type": "string"
        },
        "version": {
          "description": "Version is an optional semver constraint (e.g. \"\u003e=1.0 \u003c2.0\")",
          "type": "string"
        }
      },
      "required": [
        "module"
      ],
      "additionalProperties": false
    },
    "DocStatus": {
      "description": "Document lifecycle state (empty = lifecycle-free)",
      "type": "string",
      "enum": [
        "draft",
        "submitted",
        "cancelled"
      ]
    },
    "EntityAuth": {
      "description": "EntityAuth configures authentication for an entity.\n",
      "type": "object",
      "properties": {
        "required": {
          "type": "boolean"
        },
        "strategies": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "required"
      ],
      "additionalProperties": false
    },
    "EnvironmentMode": {
      "description": "Deployment environment mode",
      "type": "string",
      "enum": [
        "dev",
        "prod"
      ]
    },
    "EnvironmentPlane": {
      "description": "EnvironmentPlane is one resource plane endpoint of an Environment.\n",
      "type": "object",
      "properties": {
        "url": {
          "type": "string"
        }
      },
      "required": [
        "url"
      ],
      "additionalProperties": false
    },
    "ErrorCode": {
      "description": "ErrorCode is a canonical FormSpec error code string.\n",
      "type": "string",
      "enum": [
        "FORMSPEC.DOC.UPDATE_NOT_DRAFT",
        "FORMSPEC.DOC.DELETE_REFERENCED",
        "FORMSPEC.DOC.CANCEL_REFERENCED",
        "FORMSPEC.DOC.SUBMIT_NOT_DRAFT",
        "FORMSPEC.DOC.ALREADY_SUBMITTED",
        "FORMSPEC.DOC.ALREADY_CANCELLED",
        "FORMSPEC.DOC.RESERVED_FIELD",
        "FORMSPEC.DOC.CREATE_SUBMIT_NOT_AVAILABLE",
        "FORMSPEC.TXN.TRANSACTION_DATE_MISSING",
        "FORMSPEC.TXN.BACKDATE_EXCEEDED",
        "FORMSPEC.TXN.FORWARD_DATE_EXCEEDED",
        "FORMSPEC.PERIOD.CLOSED",
        "FORMSPEC.PERIOD.REOPEN_DENIED",
        "FORMSPEC.EVENT.TYPE_MISMATCH",
        "FORMSPEC.EVENT.TYPE_MISSING",
        "FORMSPEC.SAGA.OUTCOME_UNKNOWN",
        "FORMSPEC.SAGA.COMPENSATION_FAILED",
        "FORMSPEC.REF.DELETE_BLOCKED",
        "FORMSPEC.REF.CANCEL_BLOCKED",
        "FORMSPEC.PERSIST.CROSS_CATEGORY",
        "FORMSPEC.ARCHIVE.LOCKED_FOR_DELETION",
        "FORMSPEC.VALIDATE.RESERVED_ACTION_MODIFIED",
        "OBSERVABILITY_METRICS_DISABLED",
        "OBSERVABILITY_DEBUG_FORBIDDEN",
        "LOGS_FILTER_INVALID"
      ]
    },
    "EventChannel": {
      "title": "Event Channel",
      "description": "Delivery channel for an event. `audit_log`/`websocket`/`pubsub`/`reliable_event` are implemented by the delivery pipeline; `queue` is declared by the spec but not yet delivered (todo 7.7.6).",
      "type": "string",
      "enum": [
        "audit_log",
        "websocket",
        "queue",
        "pubsub",
        "reliable_event",
        "notification",
        "webhook"
      ]
    },
    "EventDecl": {
      "description": "EventDecl declares an event an entity can publish (Core §12).\n",
      "type": "object",
      "properties": {
        "deliver": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/EventDeliveryDecl"
          }
        },
        "description": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "payload": {
          "$ref": "#/$defs/PayloadDecl",
          "nullable": true
        },
        "publish": {
          "$ref": "#/$defs/PublishDecl",
          "nullable": true
        },
        "type": {
          "description": "sync | async — auto-derived from name prefix if not explicit",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "EventDeliveryDecl": {
      "description": "EventDeliveryDecl is one delivery target of an event — its \"consequence map\" entry (§12).\n",
      "type": "object",
      "properties": {
        "channel": {
          "$ref": "#/$defs/EventChannel",
          "description": "audit_log | websocket | queue | pubsub | reliable_event"
        },
        "dead_letter": {
          "$ref": "#/$defs/DeliveryTarget",
          "nullable": true
        },
        "handler": {
          "description": "Handler names an optional Service action that also delivers this event",
          "type": "string"
        },
        "idempotency_key": {
          "type": "string"
        },
        "job": {
          "description": "Job names the Service action a `queue` entry runs in the background,",
          "type": "string",
          "examples": [
            "receipt-jobs.generate-receipt"
          ]
        },
        "notification": {
          "$ref": "#/$defs/NotificationDecl",
          "description": "Notification describes what a `notification` entry delivers (todo 7.7.6).",
          "nullable": true
        },
        "retry": {
          "$ref": "#/$defs/RetryDecl",
          "nullable": true
        },
        "target": {
          "$ref": "#/$defs/DeliveryTarget",
          "description": "Target addresses an Entity/Service action for `reliable_event`.",
          "nullable": true
        },
        "webhook": {
          "$ref": "#/$defs/WebhookDeliveryDecl",
          "description": "Webhook describes where a `webhook` entry posts the event (todo 7.7.6).",
          "nullable": true
        }
      },
      "required": [
        "channel"
      ],
      "additionalProperties": false
    },
    "ExposeConfig": {
      "description": "ExposeConfig declares one external protocol surface for an Entity (D49).\nEach entry opts the entity into one protocol type. Without any expose entries,\nthe entity is purely internal (same-process services, Starlark, events only).\n",
      "type": "object",
      "properties": {
        "actions": {
          "description": "REST: list, find, create, update, delete",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "enabled": {
          "description": "for grpc/ws: true = full service",
          "type": "boolean"
        },
        "type": {
          "$ref": "#/$defs/ProtocolType",
          "description": "rest | grpc | ws"
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "ExtendStorage": {
      "description": "ExtendStorage declares that this Entity extends another entity's storage\nby adding a new JSONB column (namespace-isolated) to the target table.\n\ntarget:  \"module/entity\" of the base entity being extended\nnamespace:  unique identifier for this extension column (ext_{namespace})\n\nExtension fields MUST NOT be required (required=true is rejected at validation).\nExtension data is stored in a separate column ext_{namespace}, not in the base data JSONB.\nThis allows clean uninstall via DROP COLUMN without affecting base data.\n",
      "type": "object",
      "properties": {
        "namespace": {
          "type": "string"
        },
        "target": {
          "type": "string"
        },
        "validate": {
          "description": "Validate is an additive business rule (4.3.5): a Starlark script ref",
          "type": "string"
        }
      },
      "required": [
        "target",
        "namespace"
      ],
      "additionalProperties": false
    },
    "Field": {
      "description": "Field defines a data field on an Entity.\n@schema {title: \"Field Definition\"}\n",
      "type": "object",
      "properties": {
        "accept_data_loss": {
          "description": "AcceptDataLoss consents to a lossy type change (01-core-basic.md §4.2):",
          "type": "boolean"
        },
        "audited": {
          "type": "boolean"
        },
        "auto_fill": {
          "$ref": "#/$defs/AutoFillDecl",
          "description": "AutoFill — client-side lookup: when the relation field named in `from`",
          "nullable": true
        },
        "child": {
          "$ref": "#/$defs/ChildDecl",
          "nullable": true
        },
        "classification": {
          "$ref": "#/$defs/FieldClassification",
          "description": "1.4.3 FieldClassification — governance label (05-field-types.md §5.4)."
        },
        "computed": {
          "$ref": "#/$defs/ComputedDecl",
          "nullable": true
        },
        "currency": {
          "description": "Money (05-field-types.md §2) — only meaningful for type: money.",
          "type": "string"
        },
        "decimal_places": {
          "type": "integer",
          "nullable": true
        },
        "default": {},
        "description": {
          "description": "Help text shown to users under the input in forms (and wizard steps). Written for the end user — not a design note; it is inherited as the field's `help` wherever the field appears, so one declaration serves both surfaces.",
          "type": "string"
        },
        "encrypted": {
          "description": "1.4.6 EncryptedField — at-rest encryption marker (05-field-types.md §5.2).",
          "type": "boolean"
        },
        "enum_values": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "exclude": {
          "description": "1.4.5 FieldExclude — per-surface field exclusion (05-field-types.md §5.3).",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "immutable": {
          "type": "boolean"
        },
        "index": {
          "type": "boolean"
        },
        "masked": {
          "description": "1.4.7 MaskedField — auto-mask in response/log (05-field-types.md §5.2).",
          "type": "boolean"
        },
        "multiple": {
          "description": "How many of the declared `options` this field holds: `true` = a set (array / comma-separated list), `false` = one value. Required when `options` is declared on `json` or `string`, because those types can hold either shape.",
          "type": "boolean",
          "nullable": true
        },
        "name": {
          "description": "Field name — lowercase snake_case, unique within entity",
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "natural_key": {
          "description": "NaturalKey marks the field as the record's business identifier.",
          "type": "boolean"
        },
        "natural_key_entry": {
          "$ref": "#/$defs/NaturalKeyEntry",
          "description": "NaturalKeyEntry states who supplies the key: the engine, a person, or the engine unless a person supplies one (see the NaturalKeyEntry enum)."
        },
        "natural_key_rule": {
          "$ref": "#/$defs/NaturalKeyRuleDecl",
          "nullable": true
        },
        "options": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FieldOption"
          }
        },
        "precision": {
          "description": "Decimal precision/scale (05-field-types.md §1.2) — only meaningful for",
          "type": "integer",
          "nullable": true
        },
        "read_only": {
          "type": "boolean"
        },
        "readonly_when": {
          "type": "string"
        },
        "reason": {
          "description": "Reason states why a destructive declaration is intended (audit trail).",
          "type": "string",
          "examples": [
            "digantikan branch_id pada 2026-09"
          ]
        },
        "relation": {
          "$ref": "#/$defs/RelationDecl",
          "nullable": true
        },
        "removed": {
          "description": "Removed is the tombstone that lets a field be dropped at all (01-core-basic.md",
          "type": "boolean"
        },
        "renamed_from": {
          "description": "4.2.2 RenamedFrom — declares that this field was renamed from the given",
          "type": "string"
        },
        "required": {
          "type": "boolean"
        },
        "required_permission": {
          "description": "1.4.4 FieldPermission — field-level required_permission (05-field-types.md §5.3).",
          "type": "string"
        },
        "required_when": {
          "type": "string"
        },
        "rules": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ValidationRule"
          }
        },
        "scale": {
          "type": "integer",
          "nullable": true
        },
        "storage": {
          "$ref": "#/$defs/StorageSpec",
          "description": "1.4.11 StorageSpec — file field configuration (05-field-types.md §1.3).",
          "nullable": true
        },
        "title": {
          "description": "Caption shown to users in tables, forms, and detail pages; falls back to the humanised field name",
          "type": "string"
        },
        "tree": {
          "description": "1.4.9 TreeDecl — self-referential hierarchy marker (05-field-types.md §4).",
          "type": "boolean"
        },
        "type": {
          "$ref": "#/$defs/FieldType",
          "description": "@schema {description: \"Data type — determines storage class, renderer widget, and validation\"}"
        },
        "unique": {
          "description": "Unique declares a cross-record uniqueness constraint (unique per tenant).",
          "type": "boolean"
        },
        "unit": {
          "$ref": "#/$defs/UnitDecl",
          "description": "Unit (S12) — declares the unit dimension of a field naming/conversion",
          "nullable": true
        },
        "visible_when": {
          "description": "Client-behavior vocabulary (FormSpecExpr, frontend 08-formspec-expr.md).",
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ],
      "additionalProperties": false
    },
    "FieldClassification": {
      "description": "Data sensitivity classification for governance",
      "type": "string",
      "enum": [
        "pii",
        "financial",
        "internal"
      ]
    },
    "FieldOption": {
      "description": "FieldOption is one choice in a field's `options:` list — a closed set of\nvalues **with captions**. It exists because `enum_values` carries values\nonly: a day-of-week set declared as `[1, 2, 3]` renders as \"1, 2, 3\", so the\nauthor either writes a picker whose choices cannot be read, or a free-text\ntag input that accepts `9`.\n\n`options` is a property of the **data** (which values are legal), not of one\nform — the same reason `enum_values` lives on the Entity. A multi-value field\n(`type: json`, or a string holding a comma-separated list) can therefore be\ndeclared once and rendered, filtered, and labelled consistently.\n\n`Value` keeps the scalar's YAML type (`value: 1` stays the number 1 in the\nbundle and in the stored array, matching what the field actually holds);\n`Label` is the caption shown to users, and defaults to the value itself when\nomitted.\n",
      "type": "object",
      "properties": {
        "label": {
          "description": "Caption shown to users. Defaults to the value (humanised) when omitted.",
          "type": "string"
        },
        "value": {
          "description": "Stored value. Keep the scalar type the field stores — `value: 1` for a numeric set, not `value: \\\"1\\\"`."
        }
      },
      "required": [
        "value"
      ],
      "additionalProperties": false
    },
    "FieldRef": {
      "description": "FieldRef references another entity's field.\n",
      "type": "object",
      "properties": {
        "entity": {
          "type": "string"
        },
        "field": {
          "type": "string"
        }
      },
      "required": [
        "entity",
        "field"
      ],
      "additionalProperties": false
    },
    "FieldType": {
      "title": "Field Type",
      "description": "Data type for a field — determines storage class, renderer widget, and validation rules",
      "type": "string",
      "enum": [
        "string",
        "text",
        "richtext",
        "integer",
        "decimal",
        "money",
        "boolean",
        "enum",
        "date",
        "datetime",
        "time",
        "uuid",
        "json",
        "file",
        "attachment",
        "relation",
        "child",
        "percent",
        "number"
      ]
    },
    "FilterSpec": {
      "description": "FilterSpec is a generic filter declaration shared by every data kind that\nlists records (Table, Kanban, Listing, ApprovalInbox, …). A filter is used\nin one of two roles:\n  - `filters`: a user-adjustable control rendered in the kind's UI. If\n    `default` is set, the control is pre-seeded with that value (the user\n    can still change or clear it).\n  - `fixed_filters`: a filter the renderer always merges into the list\n    request — never rendered as a control and not user-clearable *in the UI*.\n    It is NOT an authorization boundary: the merge happens in the browser\n    (renderers/react-shadcn/src/lib/filters.ts), so a client that calls the\n    API directly simply omits it. For a filter the server enforces, use the\n    entity's `row_scope` (EntitySpec.RowScope) instead.\n\nThe resolved value is sent to the list API as `field[op]=value`, so `op`\ndefaults to \"eq\" and follows the backend filter operator set.\n\nA value can also come from the request context instead of the manifest, via\n`from` (S2/#6): `from: session` takes it from an identity attribute named by\n`attr` and is resolved server-side only (a client cannot supply or widen it),\nwhile `from: route` takes it from the query parameter named by `param` (e.g. an\nunguessable guest token, where the token itself is the credential).\n\nWhen `from` is empty the value is the LITERAL in `value`, which is what makes\na server-enforced constant expressible — e.g. a role granted `list` on orders\nbut only for `{field: status, op: in, value: \"paid,in_kitchen\"}`. `default` is\nNOT that literal: it only pre-seeds a user-adjustable control, and the user\n(or any client) can change or clear it.\n",
      "type": "object",
      "properties": {
        "all_label": {
          "description": "For select filters: caption of the \\\"All\\\" (clear) option. Default \\\"(ALL)\\\".",
          "type": "string"
        },
        "attr": {
          "description": "Identity attribute for `from: session`: principal_id | username | workspace | an application attribute.",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        },
        "default": {
          "description": "Pre-set value for a user-adjustable filter. Supports \\\"today\\\" / \\\"today()\\\", resolved by the renderer as the server's current date. NOT a server-enforced constant — use `value` for that.",
          "type": "string"
        },
        "field": {
          "type": "string"
        },
        "from": {
          "description": "Where the value comes from at request time: session (identity attribute in `attr`) or route (query parameter in `param`). Empty = the literal `value`.",
          "type": "string",
          "enum": [
            "session",
            "route"
          ]
        },
        "label": {
          "type": "string"
        },
        "op": {
          "description": "Filter operator sent to the list API",
          "type": "string",
          "enum": [
            "eq",
            "neq",
            "gt",
            "gte",
            "lt",
            "lte",
            "between",
            "in",
            "nin",
            "like",
            "ilike",
            "null",
            "notnull"
          ]
        },
        "param": {
          "description": "Query parameter name for `from: route`. Defaults to the field name.",
          "type": "string",
          "examples": [
            "token"
          ]
        },
        "show_all": {
          "description": "For select filters: show the \\\"All\\\" (clear) option. Default true.",
          "type": "boolean",
          "nullable": true
        },
        "type": {
          "description": "Filter widget type",
          "type": "string",
          "enum": [
            "text",
            "select",
            "date",
            "date_range"
          ]
        },
        "value": {
          "description": "Literal value used when `from` is empty. For `op: in`/`nin`/`between` this may be a comma-separated list, e.g. \\\"paid,in_kitchen\\\".",
          "type": "string",
          "examples": [
            "paid,in_kitchen,ready"
          ]
        },
        "via": {
          "description": "Entity the `param` value references, as \\\"\u003cmodule\u003e.\u003centity\u003e\\\" — the scope value is read from `via_field` of that record.",
          "type": "string",
          "examples": [
            "cafe-order.table-session"
          ]
        },
        "via_field": {
          "description": "Field on `via` holding the scope value (required with `via`).",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "FormAction": {
      "description": "FormAction is a custom action button on a form (Frontend §4).\n",
      "type": "object",
      "properties": {
        "action": {
          "type": "string"
        },
        "confirm": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "style": {
          "description": "primary | secondary | danger",
          "type": "string"
        }
      },
      "required": [
        "action"
      ],
      "additionalProperties": false
    },
    "FormConfirm": {
      "description": "FormConfirm is the per-form confirm override (plan confirm-dialogs.md).\n",
      "type": "object",
      "properties": {
        "create": {
          "description": "Confirm message before create — nil = inherit App default, empty string = off",
          "type": "string",
          "nullable": true
        },
        "delete": {
          "description": "Confirm message before delete — nil = inherit App default, empty string = off",
          "type": "string",
          "nullable": true
        },
        "update": {
          "description": "Confirm message before update — nil = inherit App default, empty string = off",
          "type": "string",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "FormField": {
      "description": "FormField configures a single field in a form.\nYAML uses `field:` to reference the Entity field name; JSON serializes as\n`name:` to match the TypeScript FormField interface.\n",
      "type": "object",
      "properties": {
        "compute": {
          "type": "string"
        },
        "default_from": {
          "description": "DefaultFrom seeds the field's initial value from the render context: a",
          "type": "string",
          "examples": [
            "{session.branch_id}"
          ]
        },
        "field": {
          "type": "string"
        },
        "help": {
          "description": "Help text shown under the input. Falls back to the entity field's `description`, so declaring it here is only needed to override that per-form.",
          "type": "string"
        },
        "label": {
          "description": "Caption for this field in the form; falls back to the entity field's `title`, then the humanised field name",
          "type": "string"
        },
        "placeholder": {
          "description": "Placeholder text inside the input control",
          "type": "string"
        },
        "read_only": {
          "type": "boolean"
        },
        "readonly_when": {
          "type": "string"
        },
        "required_when": {
          "type": "string"
        },
        "visible_when": {
          "type": "string"
        },
        "widget": {
          "$ref": "#/$defs/FormWidget"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "FormRender": {
      "description": "Render mode: modal (popup dialog), drawer (side panel), separate_page (full page)",
      "type": "string",
      "enum": [
        "modal",
        "drawer",
        "separate_page"
      ]
    },
    "FormRenderDecl": {
      "description": "FormRenderDecl is the design-time container declaration of a Form\n(Frontend §1.6). YAML accepts both `render: separate_page` (shorthand) and\n`render: { mode: separate_page }`; JSON always serializes the object form to\nmatch the renderer contract (`spec.render.mode`).\n",
      "oneOf": [
        {
          "description": "Shorthand render mode — e.g. \"drawer\", \"modal\", \"separate_page\"",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "$ref": "#/$defs/FormRender",
              "description": "@schema {description: \"Render mode: modal (popup dialog), drawer (side panel), separate_page (full page)\", enum: [\"modal\", \"drawer\", \"separate_page\"]}"
            },
            "picker_panel": {
              "description": "PickerPanel places the child-field picker relative to the rest of the",
              "type": "string",
              "enum": [
                "",
                "inline",
                "aside"
              ]
            }
          },
          "required": [
            "mode"
          ],
          "additionalProperties": false
        }
      ]
    },
    "FormSection": {
      "description": "FormSection groups form fields.\n",
      "type": "object",
      "properties": {
        "columns": {
          "type": "integer"
        },
        "description": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FormField"
          }
        },
        "title": {
          "type": "string"
        },
        "visible_when": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    },
    "FormSubmit": {
      "description": "FormSubmit configures the submit button and post-submit behavior.\n",
      "type": "object",
      "properties": {
        "call": {
          "description": "Call turns the form's submit into a SERVICE call instead of an entity",
          "type": "string",
          "examples": [
            "cafe-order.table-access.open"
          ]
        },
        "label": {
          "type": "string"
        },
        "message": {
          "type": "string"
        },
        "redirect": {
          "description": "Redirect is where a successful submit lands, overriding the derived list",
          "type": "string",
          "examples": [
            "/menu/{response.guest_token}"
          ]
        }
      },
      "additionalProperties": false
    },
    "FormWidget": {
      "title": "Form Widget",
      "description": "Widget rendering a form field. Closed set — every name is implemented by the renderer; omit to use the default derived from the field type.",
      "type": "string",
      "enum": [
        "input",
        "textarea",
        "richtext",
        "number",
        "decimalinput",
        "select",
        "switch",
        "radio-group",
        "combobox",
        "password",
        "slider",
        "tags",
        "select-multi-tag",
        "uuid",
        "json",
        "fileinput",
        "relation-picker",
        "datepicker",
        "datetimeinput",
        "child-grid",
        "grants-editor",
        "hidden",
        "qrcode",
        "moneyinput",
        "timeinput"
      ]
    },
    "ForwardDatePolicy": {
      "description": "ForwardDatePolicy controls how far forward a transaction_date can be set (§14a).\nDefault max_days_forward = 0 (no forward dating allowed).\n",
      "type": "object",
      "properties": {
        "max_days_forward": {
          "type": "integer"
        },
        "override_permission": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "GuardDecl": {
      "description": "GuardDecl is a condition that must be met for a transition.\nYAML accepts either an inline expression string (canonical, Core §14)\nor a map with explicit expression/message keys.\n",
      "oneOf": [
        {
          "description": "Inline guard expression — e.g. \"len(resource.items) \u003e 0 and resource.total \u003e 0\"",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "expression": {
              "type": "string"
            },
            "message": {
              "type": "string"
            }
          },
          "required": [
            "expression"
          ],
          "additionalProperties": false
        }
      ]
    },
    "HookDecl": {
      "description": "HookDecl attaches handler code to an action's before/after/on_error point,\nor an event's before_deliver/after_deliver point (Core Extended §8). A\nreserved action's own Impl (Action.Impl) is equivalent to one hook scoped\nto that action, running last in the before-phase — hooks: entries let\nother modules/scripts attach additional code to the same points, by name\nor via the \"*\" wildcard, with priority ordering (default 10; lower runs\nfirst).\n",
      "type": "object",
      "properties": {
        "action": {
          "description": "action name or \"*\" — before/after/on_error only",
          "type": "string"
        },
        "event": {
          "description": "event name or \"*\" — before_deliver/after_deliver only",
          "type": "string"
        },
        "impl": {
          "$ref": "#/$defs/ImplDecl",
          "nullable": true
        },
        "on": {
          "$ref": "#/$defs/HookTiming"
        },
        "priority": {
          "description": "0 → default 10",
          "type": "integer"
        },
        "uses": {
          "$ref": "#/$defs/UsesDecl",
          "description": "Uses declares the hook script's own access (db, resources, config,",
          "nullable": true
        }
      },
      "required": [
        "on",
        "impl"
      ],
      "additionalProperties": false
    },
    "HookTiming": {
      "description": "When the hook executes relative to the action/event",
      "type": "string",
      "enum": [
        "before",
        "after",
        "on_error",
        "before_deliver",
        "after_deliver"
      ]
    },
    "IdempotencyDecl": {
      "description": "IdempotencyDecl specifies how idempotency keys are derived.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "from": {
          "type": "string"
        }
      },
      "required": [
        "from"
      ],
      "additionalProperties": false
    },
    "ImplDecl": {
      "description": "ImplDecl specifies how an action is implemented.\n",
      "type": "object",
      "properties": {
        "ref": {
          "type": "string"
        },
        "type": {
          "$ref": "#/$defs/ImplType"
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "ImplType": {
      "title": "Implementation Type",
      "description": "How an action is implemented: script_ref (Starlark file), script (inline Starlark), native (Go), compiled (WASM), sidecar (external process)",
      "type": "string",
      "enum": [
        "script_ref",
        "script",
        "native",
        "compiled",
        "sidecar"
      ],
      "examples": [
        "native"
      ]
    },
    "IndexDecl": {
      "description": "IndexDecl declares a database index.\n",
      "type": "object",
      "properties": {
        "fields": {
          "description": "Fields covered by the index; may name relation fields",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "unique": {
          "type": "boolean"
        },
        "where": {
          "description": "Partial index predicate over field names: '\u003cfield\u003e \u003cop\u003e \u003cliteral\u003e' and/or '\u003cfield\u003e IS [NOT] NULL', joined by AND",
          "type": "string",
          "examples": [
            "status = 'open"
          ]
        }
      },
      "additionalProperties": false
    },
    "InputSet": {
      "description": "InputSet is a named, reusable list of inputs declared on the Entity.\n\nTransitions that collect the same parameters share one set through\n`params.inputs_from` instead of repeating the declaration. The set lives on\nthe Entity rather than on an action because a transition's parameters are\ndrawn from the same field pool as the record's — which is also why a \"one\nshared form for every transition\" is not expressible: permission, conditions,\napproval interception, and event emission all attach to individual\ntransitions, not to the entity.\n",
      "type": "object",
      "properties": {
        "inputs": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ParamInput"
          }
        },
        "name": {
          "description": "Set name, referenced by a transition's or action's `params.inputs_from`.",
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*$"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "IntakeChallenge": {
      "description": "IntakeChallenge configures the browser proof-of-work gate.\n",
      "type": "object",
      "properties": {
        "activate_at": {
          "description": "Fraction (0..1) of the global budget that activates the gate (mode: escalate); absent = 0.7, 0 = activate immediately",
          "type": "number",
          "examples": [
            "0.7"
          ],
          "nullable": true
        },
        "bind": {
          "description": "Extra bound attributes (subset of: ip); empty binds only the action",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[ip]"
          ]
        },
        "difficulty": {
          "$ref": "#/$defs/PowDifficulty",
          "description": "Difficulty is the proof-of-work range in leading zero bits of SHA-256.",
          "nullable": true
        },
        "global": {
          "$ref": "#/$defs/RateLimitSpec",
          "description": "Global is the pressure signal: a rate limit measured across ALL anonymous",
          "nullable": true
        },
        "mode": {
          "description": "escalate (default, on only under pressure) | always",
          "type": "string",
          "enum": [
            "escalate",
            "always"
          ],
          "examples": [
            "escalate"
          ]
        },
        "provider": {
          "description": "Challenge mechanism — only \\\"pow\\\" (self-hosted proof-of-work) is implemented",
          "type": "string",
          "enum": [
            "pow"
          ],
          "examples": [
            "pow"
          ]
        },
        "ttl": {
          "description": "Challenge lifetime (Go duration string) — bounds the replay window",
          "type": "string",
          "examples": [
            "90s"
          ]
        }
      },
      "additionalProperties": false
    },
    "IntakeSpec": {
      "description": "IntakeSpec declares protection for an App's ANONYMOUS intake surface — the\nendpoints an unauthenticated caller can reach through this App's derived\npublic grants (plan docs_internal/plan/intake-challenge-pow.md).\n\nAuthored on the App because the App is the reviewed unit of \"what may an\nanonymous caller touch\"; an Action opts in with `challenge: true`, and the\npolicy (how hard, when, how long) lives here so it has one owner. An opt-in\nwith no policy is a validation error rather than a silent no-op.\n\nEnforcement is keyed by (module, entity, action), NOT by App: an anonymous\n`_ui/entity` request carries no App (AppFromContext is empty without an\nidentity, and publicGrants() already merges every public App into a single\nmodule/entity map). Where several public Apps declare a policy the\nSTRICTEST wins — sharing a route must never weaken protection.\n",
      "type": "object",
      "properties": {
        "challenge": {
          "$ref": "#/$defs/IntakeChallenge",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "IntegratorCall": {
      "description": "IntegratorCall declares the target action to invoke.\n",
      "type": "object",
      "properties": {
        "action": {
          "description": "@schema {example: \"create\"}",
          "type": "string",
          "examples": [
            "create"
          ]
        },
        "map": {
          "description": "Map declares how the source event payload becomes the target action's",
          "type": "object",
          "additionalProperties": {}
        },
        "resource": {
          "description": "@schema {example: \"gl.journal-entry\"}",
          "type": "string",
          "examples": [
            "gl.journal-entry"
          ]
        }
      },
      "required": [
        "resource",
        "action"
      ],
      "additionalProperties": false
    },
    "IntegratorListen": {
      "description": "IntegratorListen declares the source event to react to.\n",
      "type": "object",
      "properties": {
        "event": {
          "description": "@schema {example: \"on_submit\"}",
          "type": "string",
          "examples": [
            "on_submit"
          ]
        },
        "resource": {
          "description": "@schema {example: \"sales.order\"}",
          "type": "string",
          "examples": [
            "sales.order"
          ]
        }
      },
      "required": [
        "resource",
        "event"
      ],
      "additionalProperties": false
    },
    "InvariantDecl": {
      "description": "InvariantDecl declares a property a summary projection must satisfy (S14).\nOnly `unique` is defined: it is validated against the declared indexes, so\nthe database — not discipline — keeps the property true.\n",
      "type": "object",
      "properties": {
        "message": {
          "description": "Human-readable statement of the invariant",
          "type": "string"
        },
        "unique": {
          "description": "Columns that must be unique together on this projection",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "KanbanCard": {
      "description": "KanbanCard defines what fields appear on a card.\n",
      "type": "object",
      "properties": {
        "assignee": {
          "type": "string"
        },
        "badge": {
          "type": "string"
        },
        "component": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "subtitle": {
          "type": "string"
        },
        "title": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    },
    "KanbanColumn": {
      "description": "KanbanColumn is a status lane in a kanban board.\n",
      "type": "object",
      "properties": {
        "color": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "status": {
          "type": "string"
        }
      },
      "required": [
        "status",
        "label"
      ],
      "additionalProperties": false
    },
    "Kind": {
      "title": "Resource Kind",
      "description": "Kind represents the resource kind as a PascalCase string.\n@schema {title: \"Resource Kind\"}\n",
      "type": "string",
      "enum": [
        "Seed",
        "App",
        "Module",
        "Entity",
        "Document",
        "Service",
        "Config",
        "Subscription",
        "Api",
        "KindDefinition",
        "Webhook",
        "Mockup",
        "Integrator",
        "Environment",
        "Policy",
        "Datastore",
        "Renderer",
        "VisualSpecKind",
        "PersistBackend",
        "Page",
        "Form",
        "Table",
        "Dashboard",
        "Widget",
        "Report",
        "Wizard",
        "Kanban",
        "Timeline",
        "Print",
        "Theme",
        "Listing",
        "Calendar",
        "ApprovalInbox",
        "NotificationCenter",
        "Workspace"
      ]
    },
    "KvstoreUseDecl": {
      "description": "KvstoreUseDecl specifies durable key-value store access (§11.2).\n",
      "type": "object",
      "properties": {
        "access": {
          "description": "read | read_write",
          "type": "string"
        },
        "module": {
          "type": "string"
        },
        "scope": {
          "description": "workspace | module | global",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "MenuItem": {
      "type": "object",
      "properties": {
        "children": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/MenuItem"
          }
        },
        "icon": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "module": {
          "type": "string"
        },
        "permissions": {
          "description": "RBAC: the item is withheld unless the caller holds at least one of these permissions (any-of). Enforced server-side — it never reaches a caller who lacks them.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[clinic.settings.update]"
          ]
        },
        "route": {
          "description": "raw URL escape hatch (no registered View)",
          "type": "string"
        },
        "type": {
          "description": "\"module\" = adopt-shorthand node",
          "type": "string"
        },
        "view": {
          "description": "name of a registered View resource",
          "type": "string"
        },
        "when": {
          "description": "FormSpecExpr business condition (presentation only): item hidden when false. Evaluated client-side against `user` and `today()`. NOT an authorization gate — use `permissions` for RBAC.",
          "type": "string",
          "examples": [
            "today() \u003e= '2026-01-01"
          ]
        }
      },
      "additionalProperties": false
    },
    "Metadata": {
      "description": "Metadata is common to all FormSpec resources.\n",
      "type": "object",
      "properties": {
        "annotations": {
          "type": "object",
          "additionalProperties": {}
        },
        "description": {
          "type": "string"
        },
        "labels": {
          "type": "object",
          "additionalProperties": {}
        },
        "module": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "NaturalKeyEntry": {
      "title": "Natural Key Entry",
      "description": "Who supplies the natural key: `auto_generated` (engine only), `user_entry` (a person), `auto_generated_if_empty` (engine mints it unless a value is supplied).",
      "type": "string",
      "enum": [
        "auto_generated",
        "user_entry",
        "auto_generated_if_empty"
      ]
    },
    "NaturalKeyPrefix": {
      "description": "NaturalKeyPrefix defines the prefix for a natural key.\n",
      "type": "object",
      "properties": {
        "config": {
          "type": "string"
        },
        "default": {
          "type": "string"
        },
        "value": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "NaturalKeyRuleDecl": {
      "description": "NaturalKeyRuleDecl defines how a natural key is generated.\n",
      "type": "object",
      "properties": {
        "format": {
          "type": "string"
        },
        "prefix": {
          "$ref": "#/$defs/NaturalKeyPrefix",
          "nullable": true
        },
        "reset": {
          "description": "never | yearly | monthly | daily",
          "type": "string"
        },
        "scope_field": {
          "type": "string"
        },
        "strategy": {
          "description": "sequence | custom",
          "type": "string"
        }
      },
      "required": [
        "strategy"
      ],
      "additionalProperties": false
    },
    "NotificationDecl": {
      "description": "NotificationDecl describes the in-app notification a `notification` delivery\nentry creates.\n\nEvery field is a template over the EVENT PAYLOAD (`{dotted.path}`), because\nthat is what the delivery receives: the publisher declared `payload.fields`,\nso what is available here is exactly that projection — not the record.\n",
      "type": "object",
      "properties": {
        "body": {
          "description": "Body is the notification's text, interpolated from the payload.",
          "type": "string"
        },
        "level": {
          "description": "Level is the notification's severity (info | warning | critical).",
          "type": "string",
          "enum": [
            "info",
            "warning",
            "critical"
          ],
          "examples": [
            "info"
          ]
        },
        "recipient": {
          "description": "Recipient is the payload path whose value becomes the notification's",
          "type": "string",
          "examples": [
            "customer_id"
          ]
        },
        "title": {
          "description": "Title is the notification's heading, interpolated from the payload.",
          "type": "string",
          "examples": [
            "Pesanan {number} dibayar"
          ]
        }
      },
      "required": [
        "recipient",
        "title"
      ],
      "additionalProperties": false
    },
    "OAuthProviderSettings": {
      "description": "OAuthProviderSettings configures one external auth provider.\n\n  - type: \"oidc\" (default) | \"oauth2\". OIDC uses discovery (issuer) to\n    resolve endpoints; oauth2 declares them explicitly.\n  - Presets: name \"google\" | \"github\" | \"microsoft\" fill in the endpoint\n    URLs automatically — only client_id/client_secret are required.\n  - Custom: declare type + authorize_url/token_url/userinfo_url.\n",
      "type": "object",
      "properties": {
        "authorize_url": {
          "description": "AuthorizeURL / TokenURL / UserInfoURL for type: oauth2 (custom).",
          "type": "string"
        },
        "client_id": {
          "description": "OAuth client ID",
          "type": "string"
        },
        "client_secret": {
          "description": "OAuth client secret (secret — never exposed to the renderer)",
          "type": "string"
        },
        "issuer": {
          "description": "Issuer is the OIDC issuer URL (type: oidc) — discovery resolves",
          "type": "string"
        },
        "scopes": {
          "description": "OAuth scopes (default: openid email profile)",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "token_url": {
          "type": "string"
        },
        "type": {
          "description": "@schema {enum: [\"oidc\", \"oauth2\"], default: \"oidc\"}",
          "type": "string",
          "enum": [
            "oidc",
            "oauth2"
          ]
        },
        "userinfo_url": {
          "type": "string"
        }
      },
      "required": [
        "client_id",
        "client_secret"
      ],
      "additionalProperties": false
    },
    "OnDelete": {
      "description": "Referential action on target delete",
      "type": "string",
      "enum": [
        "restrict",
        "cascade",
        "set_null"
      ]
    },
    "PageBinds": {
      "description": "PageBinds declares the backend footprint of a `mode: custom` page\n(frontend/06-page-kinds.md §13) — the same role as `needs:` on a component\nblock (frontend/07-component-kinds.md §4). Calls outside `binds` fail\nclient-side and are never authorized server-side either.\n",
      "type": "object",
      "properties": {
        "actions": {
          "description": "Actions the page may invoke, as \"module.entity.action\" (or wildcard).",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "entities": {
          "description": "Entities the page may read/write, as \"module.entity\" refs.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "subscribe": {
          "description": "Subscribe channels (entity refs) the page may subscribe to.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "PageBlock": {
      "description": "PageBlock is a compositional unit within a Page.\n",
      "type": "object",
      "properties": {
        "component": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "form": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "html": {
          "type": "string"
        },
        "section": {
          "$ref": "#/$defs/SectionBlock",
          "nullable": true
        },
        "table": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "widget": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "PageLayout": {
      "description": "PageLayout controls block arrangement on a page.\n",
      "type": "object",
      "properties": {
        "columns": {
          "type": "integer"
        },
        "mode": {
          "description": "Layout mode. `split` = master-detail (master list left, detail right).",
          "type": "string",
          "enum": [
            "",
            "split"
          ]
        }
      },
      "additionalProperties": false
    },
    "PageTab": {
      "description": "PageTab is one tab on a tabbed page (Frontend §3, tabs variant).\n",
      "type": "object",
      "properties": {
        "component": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "form": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "label": {
          "type": "string"
        },
        "table": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        }
      },
      "required": [
        "label"
      ],
      "additionalProperties": false
    },
    "ParamInput": {
      "description": "ParamInput is one declared input of an action or transition.\n",
      "type": "object",
      "properties": {
        "compute": {
          "type": "string"
        },
        "default": {
          "description": "Default seeds the input before the user touches it."
        },
        "enum_values": {
          "description": "EnumValues / Options / Multiple describe an ad-hoc input's choice set, the",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "help": {
          "description": "Help is the user-facing hint rendered under the input. On an Entity field",
          "type": "string"
        },
        "label": {
          "description": "Label overrides the caption. Falls back to the Entity field's `title`,",
          "type": "string"
        },
        "multiple": {
          "type": "boolean",
          "nullable": true
        },
        "name": {
          "description": "Parameter name, and the wire key in the request body. Matching an Entity field name makes this a REFERENCE to that field (inheriting type/enum/cardinality, and persisting the collected value); otherwise the input is ad-hoc.",
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "options": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FieldOption"
          }
        },
        "persist": {
          "description": "Persist overrides the destination of a collected value. Absent means the",
          "type": "boolean",
          "nullable": true
        },
        "placeholder": {
          "description": "Placeholder is the empty-state hint inside the input.",
          "type": "string"
        },
        "readonly_when": {
          "type": "string"
        },
        "required": {
          "description": "Required marks the input as unconditionally required. `RequiredWhen`",
          "type": "boolean"
        },
        "required_when": {
          "type": "string"
        },
        "rules": {
          "description": "Rules constrains the collected value. Merged with the Entity field's own",
          "type": "array",
          "items": {
            "$ref": "#/$defs/ValidationRule"
          }
        },
        "type": {
          "$ref": "#/$defs/FieldType",
          "description": "Type is the data type of an AD-HOC input. Required when `name` matches no"
        },
        "visible_when": {
          "description": "Client-behavior vocabulary (`FormSpecExpr`), identical to a Form field's",
          "type": "string"
        },
        "widget": {
          "$ref": "#/$defs/FormWidget",
          "description": "Widget overrides the widget derived from the field's type. A CLOSED set"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "ParamValidation": {
      "description": "ParamValidation validates an action parameter.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "rules": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ValidationRule"
          }
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "ParamsDecl": {
      "description": "ParamsDecl declares what an action or transition accepts: the rules a request\nbody must satisfy (`validate`), and — since the action-input contract — the\ninputs a renderer should COLLECT (`inputs`).\n",
      "type": "object",
      "properties": {
        "inputs": {
          "description": "Inputs declares the parameters richly enough to render: label, widget, and",
          "type": "array",
          "items": {
            "$ref": "#/$defs/ParamInput"
          }
        },
        "inputs_from": {
          "description": "InputsFrom pulls in named `input_sets:` declared on the owning Entity, so",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "render": {
          "$ref": "#/$defs/ParamsRenderHint",
          "description": "Render carries the design-time container decision. Absent means the",
          "nullable": true
        },
        "validate": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ParamValidation"
          }
        }
      },
      "additionalProperties": false
    },
    "ParamsRenderHint": {
      "description": "ParamsRenderHint carries the container decision for an input form, and is\ndeliberately a design-time choice — the same locking `Form.render` has, and\nfor the same reason: whether a dialog or a page appears is a layout decision\na manifest author makes, not something the runtime should second-guess.\n\nWhen absent the renderer derives the container from the input count, matching\n`deriveFormRenderMode` (≤5 modal, 5–12 drawer, \u003e12 separate_page).\n",
      "type": "object",
      "properties": {
        "mode": {
          "description": "Input-form container. Design-time decision, not switchable at runtime.",
          "type": "string",
          "enum": [
            "modal",
            "drawer",
            "separate_page"
          ]
        }
      },
      "additionalProperties": false
    },
    "PayloadDecl": {
      "description": "PayloadDecl declares which entity fields are carried in the event payload (§12).\n",
      "type": "object",
      "properties": {
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "PersistSpec": {
      "description": "PersistSpec controls how an entity is stored (Core §19).\n",
      "type": "object",
      "properties": {
        "category": {
          "description": "operational | financial | compliance | analytics | master | archive",
          "type": "string"
        },
        "indexes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/IndexDecl"
          }
        },
        "raw_ddl": {
          "description": "RawDDL holds storage-level DDL the spec language does not express —",
          "type": "array",
          "items": {
            "$ref": "#/$defs/RawDDLDecl"
          }
        },
        "soft_delete": {
          "description": "SoftDelete defaults to true; nil means \"not set\" so a persist block",
          "type": "boolean",
          "nullable": true
        },
        "table": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PickerDecl": {
      "description": "PickerDecl declares that a child field is filled by picking records from\nanother entity.\n",
      "type": "object",
      "properties": {
        "display": {
          "$ref": "#/$defs/PickerDisplay",
          "description": "Display describes how a source record is presented as a tile."
        },
        "entity": {
          "description": "Entity is the source entity rows are picked from (`module.entity` or a",
          "type": "string",
          "examples": [
            "cafe-master.menu-item"
          ]
        },
        "filter": {
          "description": "Filter is an equality pre-filter applied to the source list request.",
          "type": "object",
          "additionalProperties": {},
          "examples": [
            "{\\\"is_available\\\": \\\"true\\\"}"
          ]
        },
        "lookup": {
          "$ref": "#/$defs/PickerLookup",
          "description": "Lookup enriches each picked row with a value read from a related entity",
          "nullable": true
        },
        "map": {
          "$ref": "#/$defs/PickerMap",
          "description": "Map describes what gets written into the row."
        }
      },
      "required": [
        "entity",
        "display",
        "map"
      ],
      "additionalProperties": false
    },
    "PickerDisplay": {
      "description": "PickerDisplay is the presentation half of a picker: what the user sees.\n",
      "type": "object",
      "properties": {
        "category_field": {
          "description": "Source relation/enum field rendered as filter chips.",
          "type": "string",
          "examples": [
            "menu_category_id"
          ]
        },
        "columns": {
          "description": "Tile grid columns, 2–4 (default 3).",
          "type": "integer",
          "examples": [
            "3"
          ]
        },
        "description_field": {
          "description": "@schema {example: \"description\"}",
          "type": "string",
          "examples": [
            "description"
          ]
        },
        "empty_text": {
          "description": "@schema {example: \"Belum ada data\"}",
          "type": "string",
          "examples": [
            "Belum ada data"
          ]
        },
        "image_field": {
          "description": "Source field holding an image: a file/attachment field (served from the entity file route) or a string URL.",
          "type": "string",
          "examples": [
            "photo"
          ]
        },
        "name_field": {
          "description": "Source field used as the tile title (default \\\"name\\\").",
          "type": "string",
          "examples": [
            "name"
          ]
        },
        "search": {
          "description": "Client-side search over the tile title.",
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "PickerLookup": {
      "description": "PickerLookup enriches a picked row with a value read from a RELATED entity —\none record per picked row, matched by a key.\n\nGeneric on purpose, and that is the whole point: \"read one value per row from\na table keyed by that row\" is one shape, not a food-ordering feature. Change\nthe nouns and it is a per-outlet price, a per-region tax rate, a per-warehouse\nstock level, a per-clinic fee, a per-tenant quota or a localized label. The\npicker's own entity supplies the ROWS; the lookup supplies the VALUE that goes\nwith each row.\n\nIt is declared on the picker (not on the entity) because the picker is what\ncauses the fetch, so the declaration and the enforcement cannot come from two\ndifferent places.\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "Entity is the related entity the value is read from (`module.entity` or a",
          "type": "string",
          "examples": [
            "cafe-master.menu-item-price"
          ]
        },
        "field": {
          "description": "Field is the field on `entity` whose value is used.",
          "type": "string",
          "examples": [
            "price"
          ]
        },
        "filter": {
          "description": "Filter narrows the lookup list IN THE BROWSER. Values interpolate",
          "type": "object",
          "additionalProperties": {},
          "examples": [
            "{\\\"is_active\\\": \\\"true\\\"}"
          ]
        },
        "key": {
          "description": "Key is the field on `entity` matched against the picked row's source id",
          "type": "string",
          "examples": [
            "menu_item_id"
          ]
        },
        "scope": {
          "description": "Scope is the SERVER-ENFORCED row scope for reads of `entity` caused by this",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilterSpec"
          }
        }
      },
      "required": [
        "entity",
        "key",
        "field"
      ],
      "additionalProperties": false
    },
    "PickerMap": {
      "description": "PickerMap is the write half of a picker: which row field receives what.\n",
      "type": "object",
      "properties": {
        "lookup_field": {
          "description": "LookupField receives `lookup.field` for the picked row (snapshot).",
          "type": "string",
          "examples": [
            "unit_price_snapshot"
          ]
        },
        "max_quantity": {
          "description": "Upper bound per row (default 99).",
          "type": "integer",
          "examples": [
            "20"
          ]
        },
        "name_field": {
          "description": "NameField receives the source record's display name (snapshot).",
          "type": "string",
          "examples": [
            "name_snapshot"
          ]
        },
        "note_field": {
          "description": "NoteField is a free-text per-row note (typed by the user, not copied).",
          "type": "string",
          "examples": [
            "note"
          ]
        },
        "quantity_field": {
          "description": "QuantityField accumulates the picked amount. When omitted, a picked row",
          "type": "string",
          "examples": [
            "quantity"
          ]
        },
        "ref_field": {
          "description": "RefField is the row's relation field pointing back at the source record.",
          "type": "string",
          "examples": [
            "menu_item_id"
          ]
        },
        "source_name_field": {
          "description": "SourceNameField overrides which *source* field the name snapshot reads from",
          "type": "string",
          "examples": [
            "title"
          ]
        }
      },
      "required": [
        "ref_field"
      ],
      "additionalProperties": false
    },
    "PolicyApproval": {
      "description": "PolicyApproval declares an approval rule for a class of implementation types.\n",
      "type": "object",
      "properties": {
        "approver_roles": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "approvers": {
          "type": "integer"
        },
        "impl": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ImplType"
          }
        }
      },
      "required": [
        "approvers"
      ],
      "additionalProperties": false
    },
    "PowDifficulty": {
      "description": "PowDifficulty is the proof-of-work difficulty range (leading zero bits of\nSHA-256). Max is capped at 32 in validation: past that the gate is an\noutage, not a filter.\n",
      "type": "object",
      "properties": {
        "max": {
          "description": "Leading zero bits when saturated (upper bound)",
          "type": "integer",
          "examples": [
            "22"
          ]
        },
        "min": {
          "description": "Leading zero bits when idle (lower bound)",
          "type": "integer",
          "examples": [
            "16"
          ]
        }
      },
      "required": [
        "min",
        "max"
      ],
      "additionalProperties": false
    },
    "PrimitiveType": {
      "description": "ctx.* primitive type this datastore backs",
      "type": "string",
      "enum": [
        "db",
        "cache",
        "lock",
        "queue",
        "pubsub",
        "storage",
        "config",
        "kvstore",
        "log"
      ]
    },
    "PrintBodyItem": {
      "description": "PrintBodyItem is one element in the Print body\n(fields | separator | child_table | totals | qrcode).\n",
      "type": "object",
      "properties": {
        "child_table": {
          "$ref": "#/$defs/PrintChildTable",
          "nullable": true
        },
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "qrcode": {
          "$ref": "#/$defs/PrintQrcode",
          "description": "Qrcode renders a scannable QR code (gap #3 / S4: a table card or a",
          "nullable": true
        },
        "separator": {
          "type": "string"
        },
        "totals": {
          "$ref": "#/$defs/PrintTotals",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "PrintChildTable": {
      "description": "PrintChildTable renders a child-table field in a Print body.\n",
      "type": "object",
      "properties": {
        "columns": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "field": {
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "PrintCustomPaper": {
      "description": "PrintCustomPaper is a custom paper dimension.\n",
      "type": "object",
      "properties": {
        "height": {
          "type": "number"
        },
        "unit": {
          "type": "string"
        },
        "width": {
          "type": "number"
        }
      },
      "required": [
        "width",
        "height",
        "unit"
      ],
      "additionalProperties": false
    },
    "PrintFooter": {
      "description": "PrintFooter is the declarative footer block of a Print document.\n",
      "type": "object",
      "properties": {
        "text": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PrintFormat": {
      "title": "Print Format",
      "description": "Output format for a Print document. Closed set — pdf/thermal are served server-side, html client-side; dotmatrix is not implemented and is rejected.",
      "type": "string",
      "enum": [
        "pdf",
        "thermal",
        "dotmatrix",
        "html"
      ]
    },
    "PrintHeader": {
      "description": "PrintHeader is the declarative header block of a Print document.\n",
      "type": "object",
      "properties": {
        "logo": {
          "type": "boolean"
        },
        "subtitle": {
          "type": "string"
        },
        "title": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PrintMode": {
      "title": "Print Mode",
      "description": "How the document is invoked. `preview` (default) opens the preview dialog; `direct` runs the print/download action as soon as the record loads.",
      "type": "string",
      "enum": [
        "preview",
        "direct"
      ]
    },
    "PrintOutput": {
      "description": "PrintOutput selects the rendering pipeline and paper.\n",
      "type": "object",
      "properties": {
        "format": {
          "$ref": "#/$defs/PrintFormat",
          "description": "pdf | thermal | dotmatrix | html"
        },
        "paper": {
          "$ref": "#/$defs/PrintPaper",
          "nullable": true
        },
        "print_mode": {
          "$ref": "#/$defs/PrintMode",
          "description": "Mode selects how the document is invoked. Empty means `preview` — the"
        }
      },
      "required": [
        "format"
      ],
      "additionalProperties": false
    },
    "PrintPaper": {
      "description": "PrintPaper declares the paper size for a print output.\n",
      "type": "object",
      "properties": {
        "custom": {
          "$ref": "#/$defs/PrintCustomPaper",
          "nullable": true
        },
        "margin": {
          "type": "string"
        },
        "size": {
          "description": "A4 | A5 | thermal_58mm | ...",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PrintQrcode": {
      "description": "PrintQrcode is a QR code element in a Print body.\n",
      "type": "object",
      "properties": {
        "absolute": {
          "description": "Absolute prepends the origin the document is printed from, so the code",
          "type": "boolean"
        },
        "label": {
          "description": "@schema {example: \"Scan untuk struk digital\"}",
          "type": "string",
          "examples": [
            "Scan untuk struk digital"
          ]
        },
        "payload": {
          "description": "Text the QR encodes. `{dotted.path}` tokens are interpolated from the record, exactly like `header.title`/`footer.text`.",
          "type": "string",
          "examples": [
            "/status/{guest_token}"
          ],
          "minLength": 1
        },
        "size_mm": {
          "description": "QR side length in millimetres (default 30). Thermal maps it to a module size instead of a physical size.",
          "type": "integer",
          "examples": [
            "30"
          ],
          "minimum": 0
        }
      },
      "required": [
        "payload"
      ],
      "additionalProperties": false
    },
    "PrintTotals": {
      "description": "PrintTotals renders a totals line in a Print body.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "format": {
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "ProtocolType": {
      "description": "External protocol type",
      "type": "string",
      "enum": [
        "rest",
        "grpc",
        "ws"
      ]
    },
    "PublicEntityDecl": {
      "description": "PublicEntityDecl grants anonymous access to one entity's actions on a public\nApp's surface (S3). Entity is \"\u003cmodule\u003e/\u003centity\u003e\"; the module MUST be one of\nthe App's spec.modules, so a grant can never reach outside the App bundle.\n",
      "type": "object",
      "properties": {
        "actions": {
          "description": "Closed set: list, find, create, update, delete",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[list, find]"
          ]
        },
        "entity": {
          "description": "@schema {example: \"cafe-master/menu-item\"}",
          "type": "string",
          "examples": [
            "cafe-master/menu-item"
          ]
        },
        "scope": {
          "description": "Scope is the row filter anonymous reads of this entity must satisfy on",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilterSpec"
          }
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "PublishDecl": {
      "description": "PublishDecl configures how an event is published.\n",
      "type": "object",
      "properties": {
        "durable": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "RateLimitSpec": {
      "description": "1.4.1 RateLimitSpec — per-resource or per-action rate limit (02-core-extended.md §17).\n",
      "type": "object",
      "properties": {
        "max": {
          "type": "integer"
        },
        "per": {
          "description": "e.g. \"1s\", \"1m\", \"1h\"",
          "type": "string"
        },
        "scope": {
          "description": "tenant | user | ip | global",
          "type": "string"
        },
        "strategy": {
          "description": "sliding_window | token_bucket",
          "type": "string"
        }
      },
      "required": [
        "max",
        "per"
      ],
      "additionalProperties": false
    },
    "RawDDLDecl": {
      "description": "RawDDLDecl is one storage-level DDL statement declared on an Entity\n(01-core-basic.md §4.3).\n",
      "type": "object",
      "properties": {
        "ddl": {
          "description": "DDL is one statement valid on every driver.",
          "type": "string",
          "examples": [
            "CREATE INDEX idx_invoice_date ON invoice(transaction_date)"
          ]
        },
        "ddl_by": {
          "description": "DDLByDialect holds per-driver variants, for DDL that cannot be written",
          "type": "object",
          "additionalProperties": {}
        },
        "name": {
          "description": "Name identifies the statement for recording and reporting.",
          "type": "string",
          "examples": [
            "menu-price-unique"
          ],
          "minLength": 1,
          "pattern": "^[a-z][a-z0-9_-]*$"
        },
        "reason": {
          "description": "Reason states why the DDL is needed (audit trail).",
          "type": "string",
          "examples": [
            "satu harga per menu per cabang"
          ]
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "RebuildSpec": {
      "description": "RebuildSpec describes how a summary entity is rebuilt from its durable\nsource event/record stream.\n",
      "type": "object",
      "properties": {
        "since": {
          "type": "string"
        },
        "strategy": {
          "description": "full | partial | none",
          "type": "string"
        },
        "window": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "RegisteredViewDecl": {
      "description": "RegisteredViewDecl is one extra view an App exposes beyond its menu\n(App.spec.registered_views — plan docs_internal/plan/registered-views.md).\nExactly one of Entity/View is set:\n\n  - Entity grants every derived view of one entity (list/detail/create/edit);\n  - View grants one registered navigable view by name.\n\nEntity accepts \"module/entity\" or \"module.entity\" (normalized via\nNormalizeEntityRef); View accepts \"module/name\". The module MUST be one of the\nApp's spec.modules, so a declaration can never reach outside the App bundle.\nExistence of the referenced entity/view is checked at resolve time (it needs\nthe UI/entity registries).\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "@schema {example: \"cafe-master/menu-item\"}",
          "type": "string",
          "examples": [
            "cafe-master/menu-item"
          ]
        },
        "view": {
          "description": "@schema {example: \"cafe-order/menu-catalog\"}",
          "type": "string",
          "examples": [
            "cafe-order/menu-catalog"
          ]
        }
      },
      "additionalProperties": false
    },
    "RegistrationSettings": {
      "description": "RegistrationSettings configures the workspace-level self-service sign-up\npolicy (auth redesign Fase 4). Per-workspace — applies to every App in the\nworkspace.\n\n  - open     (default): sign-up creates an active user with DefaultRole.\n  - approval: sign-up creates a pending user; an admin approves + assigns\n    the role before the user can log in.\n  - closed:   self-service sign-up is disabled; admins create users.\n",
      "type": "object",
      "properties": {
        "default_role": {
          "description": "DefaultRole is assigned on sign-up when Policy is \"open\" (e.g. \"user\").",
          "type": "string"
        },
        "policy": {
          "description": "@schema {enum: [\"open\", \"approval\", \"closed\"], default: \"open\"}",
          "type": "string",
          "enum": [
            "open",
            "approval",
            "closed"
          ]
        }
      },
      "additionalProperties": false
    },
    "RelationDecl": {
      "description": "RelationDecl defines a relation to another entity.\n@schema {title: \"Relation Declaration\"}\n",
      "type": "object",
      "properties": {
        "foreign_key": {
          "type": "string"
        },
        "on_delete": {
          "$ref": "#/$defs/OnDelete",
          "description": "restrict | cascade | set_null (v0.3.0)"
        },
        "resource": {
          "description": "Target entity \\\"module/entity\\\" or just \\\"entity\\\" within same module",
          "type": "string"
        },
        "snapshot": {
          "description": "Snapshot copies master financial fields to the transaction at",
          "type": "array",
          "items": {
            "$ref": "#/$defs/SnapshotField"
          }
        },
        "type": {
          "description": "Relation type: belongs_to (FK on this entity), has_many (FK on target), has_one (FK on target, unique)",
          "type": "string",
          "enum": [
            "belongs_to",
            "has_many",
            "has_one"
          ]
        }
      },
      "required": [
        "type",
        "resource"
      ],
      "additionalProperties": false
    },
    "ReportAggregate": {
      "title": "Report Aggregate",
      "description": "Aggregation applied to a report column. Closed set — mirrors the Query Builder's aggregate functions.",
      "type": "string",
      "enum": [
        "sum",
        "avg",
        "count",
        "min",
        "max"
      ]
    },
    "ReportColumn": {
      "description": "ReportColumn is a column in a report output.\n",
      "type": "object",
      "properties": {
        "aggregate": {
          "$ref": "#/$defs/ReportAggregate",
          "description": "Aggregate is a closed set (S16) — mirrors the Query Builder's aggregate"
        },
        "field": {
          "type": "string"
        },
        "format": {
          "$ref": "#/$defs/ReportFormat",
          "description": "Format is a closed set (S16) — every name is implemented by the report"
        },
        "label": {
          "type": "string"
        },
        "widget": {
          "$ref": "#/$defs/TableCellWidget",
          "description": "Widget renders the cell like a table cell (S16) — the same closed set as"
        }
      },
      "required": [
        "field",
        "label"
      ],
      "additionalProperties": false
    },
    "ReportFormat": {
      "title": "Report Format",
      "description": "Value formatter for a report column. Closed set — every name is implemented by the report renderer.",
      "type": "string",
      "enum": [
        "currency",
        "date",
        "datetime",
        "percentage"
      ]
    },
    "ReportGroup": {
      "description": "ReportGroup defines a grouping level in a report.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "label": {
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "ReportParam": {
      "description": "ReportParam is a filterable input for a report.\n",
      "type": "object",
      "properties": {
        "default": {},
        "field": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "required": {
          "type": "boolean"
        },
        "type": {
          "$ref": "#/$defs/ReportParamType"
        }
      },
      "required": [
        "field",
        "label",
        "type"
      ],
      "additionalProperties": false
    },
    "ReportParamType": {
      "title": "Report Param Type",
      "description": "Input type for a report parameter. Closed set — every name is implemented by the report renderer.",
      "type": "string",
      "enum": [
        "text",
        "date",
        "datetime",
        "select",
        "relation"
      ]
    },
    "ReportSource": {
      "description": "ReportSource declares the report's data source + parameterized filter.\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "@schema {example: \"billing.order\"}",
          "type": "string",
          "examples": [
            "billing.order"
          ]
        },
        "filter": {
          "description": "Filter maps a list-API filter field to a literal value or a `\":param\"`",
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "ReportTotal": {
      "description": "ReportTotal defines a total/aggregate row.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "fn": {
          "description": "sum | avg | count | min | max",
          "type": "string"
        },
        "label": {
          "type": "string"
        }
      },
      "required": [
        "label",
        "field",
        "fn"
      ],
      "additionalProperties": false
    },
    "RetryDecl": {
      "description": "RetryDecl configures retry behavior for reliable event delivery.\n",
      "type": "object",
      "properties": {
        "backoff": {
          "description": "exponential | linear | fixed",
          "type": "string"
        },
        "initial_delay_ms": {
          "type": "integer"
        },
        "max": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "RoundingMode": {
      "description": "RoundingMode is the rounding strategy for money/decimal arithmetic.\n",
      "type": "string",
      "enum": [
        "half_even",
        "half_up",
        "half_down",
        "up",
        "down"
      ]
    },
    "ScopeDecl": {
      "description": "ScopeDecl declares that an entity's rows are partitioned along a named\ndimension (S5). `Field` is the field on this entity that carries the dimension\nvalue; `Required` asserts that every row carries one.\n",
      "type": "object",
      "properties": {
        "dimension": {
          "description": "Dimension name, e.g. branch / tenant / region",
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "enforced": {
          "description": "Who keeps reads inside the dimension: session (default), route, none (cross-cutting by design), external (public grant / create_scope).",
          "type": "string",
          "enum": [
            "session",
            "route",
            "none",
            "external"
          ]
        },
        "field": {
          "description": "Field on this entity carrying the dimension value",
          "type": "string"
        },
        "required": {
          "description": "Every row must carry a dimension value; requires the field itself to be required",
          "type": "boolean"
        }
      },
      "required": [
        "dimension",
        "field"
      ],
      "additionalProperties": false
    },
    "SectionBlock": {
      "description": "SectionBlock is a declarative presentation section inside a Page\n(frontend/06-page-kinds.md §1). Sections are generic — reusable in any App\n(marketing/hero, no-nav, sidebar-nav, ...): pure presentation, no data\nbinding, no auth, and zero styling fields — every visual token lives in\nkind: Theme (frontend/05-app-kinds.md §5), never inline.\n",
      "type": "object",
      "properties": {
        "align": {
          "description": "Align controls text alignment of title/subtitle/items — left (default)",
          "type": "string",
          "enum": [
            "left",
            "center",
            "right"
          ]
        },
        "autoplay": {
          "description": "Autoplay + IntervalMS drive carousel auto-advance (default off / 5000ms).",
          "type": "boolean"
        },
        "columns": {
          "description": "Columns controls the grid width for feature_grid / card (default 3).",
          "type": "integer"
        },
        "cta": {
          "$ref": "#/$defs/SectionCTA",
          "nullable": true
        },
        "image": {
          "description": "@schema {example: \"assets/hero.png\"}",
          "type": "string",
          "examples": [
            "assets/hero.png"
          ]
        },
        "interval_ms": {
          "type": "integer"
        },
        "items": {
          "description": "Items is the content list for feature_grid / card / carousel.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/SectionItem"
          }
        },
        "subtitle": {
          "description": "@schema {example: \"Satu platform untuk jadwal, pasien, dan tagihan.\"}",
          "type": "string",
          "examples": [
            "Satu platform untuk jadwal, pasien, dan tagihan."
          ]
        },
        "title": {
          "description": "@schema {example: \"Kelola klinik Anda\"}",
          "type": "string",
          "examples": [
            "Kelola klinik Anda"
          ]
        },
        "type": {
          "description": "Section block type — closed set.",
          "type": "string",
          "enum": [
            "hero",
            "feature_grid",
            "card",
            "carousel",
            "cta"
          ]
        },
        "variant": {
          "description": "@schema {example: \"primary\"}",
          "type": "string",
          "examples": [
            "primary"
          ]
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "SectionCTA": {
      "description": "SectionCTA is one call-to-action link inside a section block.\n",
      "type": "object",
      "properties": {
        "href": {
          "description": "@schema {example: \"/app\"}",
          "type": "string",
          "examples": [
            "/app"
          ]
        },
        "label": {
          "description": "@schema {example: \"Mulai\"}",
          "type": "string",
          "examples": [
            "Mulai"
          ]
        },
        "variant": {
          "description": "@schema {example: \"primary\", enum: [\"primary\", \"secondary\", \"ghost\"]}",
          "type": "string",
          "enum": [
            "primary",
            "secondary",
            "ghost"
          ],
          "examples": [
            "primary"
          ]
        }
      },
      "required": [
        "label",
        "href"
      ],
      "additionalProperties": false
    },
    "SectionItem": {
      "description": "SectionItem is one content entry in a feature_grid / card / carousel block.\n",
      "type": "object",
      "properties": {
        "cta": {
          "$ref": "#/$defs/SectionCTA",
          "nullable": true
        },
        "icon": {
          "description": "Icon is a lucide icon name (renderer-specific; closed to the shell's",
          "type": "string"
        },
        "image": {
          "type": "string"
        },
        "text": {
          "type": "string"
        },
        "title": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "SeedEntity": {
      "description": "SeedEntity declares the records to insert for a single entity.\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "Entity name inside metadata.module",
          "type": "string",
          "examples": [
            "menu-item"
          ]
        },
        "records": {
          "description": "Raw entity payloads (same shape as an API create body); supports `$ref` for relations and `$asset` for file fields",
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": {}
          }
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "Settings": {
      "description": "Settings is the typed global presentation/config namespace. It is declared\nonce on a workspace/App `kind: Config` manifest under `settings:` and\nresolved with standard defaults so behavior is consistent across every\ncomponent even when unset. Renderers/backends read these values instead of\nguessing per component (01-core-basic.md §10, 05-field-types.md §2).\n",
      "type": "object",
      "properties": {
        "auth": {
          "$ref": "#/$defs/AuthSettings",
          "description": "Auth configures external authentication providers (auth redesign Fase 5",
          "nullable": true
        },
        "currency": {
          "$ref": "#/$defs/CurrencySettings",
          "description": "Currency is the default money currency for the workspace (ISO-4217 code,",
          "nullable": true
        },
        "date_format": {
          "description": "DateFormat is the display date format (e.g. \"YYYY-MM-DD\", \"DD/MM/YYYY\").",
          "type": "string"
        },
        "decimal_scale": {
          "description": "DecimalScale is the default number of digits after the decimal point for",
          "type": "integer"
        },
        "locale": {
          "description": "Locale is the IETF BCP-47 locale used for number/date formatting",
          "type": "string"
        },
        "registration": {
          "$ref": "#/$defs/RegistrationSettings",
          "description": "Registration is the workspace-level self-service sign-up policy",
          "nullable": true
        },
        "rounding": {
          "description": "Rounding is the default rounding mode for money/decimal arithmetic:",
          "type": "string"
        },
        "timezone": {
          "description": "Timezone is the IANA timezone name (e.g. \"UTC\", \"Asia/Jakarta\").",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "SlotContract": {
      "description": "SlotContract defines the props contract for a slot.\n",
      "type": "object",
      "properties": {
        "optional_props": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "required_props": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "SlotDecl": {
      "description": "SlotDecl declares a named slot with its data contract (02-visual-spec-kind.md §4).\n",
      "type": "object",
      "properties": {
        "contract": {
          "$ref": "#/$defs/SlotContract",
          "nullable": true
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "SnapshotField": {
      "description": "SnapshotField copies one master field into the transaction at create/submit\n(02-core-extended.md §1.1, todo 7.10).\n",
      "type": "object",
      "properties": {
        "as": {
          "description": "As is the target field name on the transaction (default = From).",
          "type": "string"
        },
        "from": {
          "description": "From is the master field name to copy.",
          "type": "string"
        }
      },
      "required": [
        "from"
      ],
      "additionalProperties": false
    },
    "SoftDeactivateDecl": {
      "description": "1.4.10 SoftDeactivateDecl — soft-deactivation pattern for master entities\n(02-core-extended.md §19). Adds is_active field + deactivate/reactivate actions.\n",
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "StateDecl": {
      "description": "StateDecl defines a named state.\n",
      "type": "object",
      "properties": {
        "description": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "label"
      ],
      "additionalProperties": false
    },
    "StateMachine": {
      "description": "StateMachine defines entity lifecycle states and transitions.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "initial": {
          "type": "string"
        },
        "states": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/StateDecl"
          }
        },
        "transitions": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TransitionDecl"
          }
        }
      },
      "required": [
        "field",
        "initial"
      ],
      "additionalProperties": false
    },
    "StepEscalation": {
      "description": "StepEscalation configures the timeout and the takeover that follows it for one\nstep.\n\nBoth fields are required together. The only escalation effect the engine\nimplements is REASSIGNMENT, so an `after` with nothing to reassign to — or a\nreassign with no timeout to fire — would pass through silently and change\nnothing at all. That is the same \"declaration with no effect\" shape this file\nkeeps refusing, and it is why `notify_roles` was removed: notification delivery\ndoes not exist, so the field could never have done anything.\n",
      "type": "object",
      "properties": {
        "after": {
          "description": "@schema {example: \"48h\"}",
          "type": "string",
          "examples": [
            "48h"
          ]
        },
        "reassign": {
          "description": "Reassign names the DUTY that gains approval rights when the timeout fires.",
          "type": "string",
          "examples": [
            "manager-check"
          ]
        }
      },
      "required": [
        "after",
        "reassign"
      ],
      "additionalProperties": false
    },
    "StorageSpec": {
      "description": "1.4.11 StorageSpec — file field configuration (05-field-types.md §1.3).\nOnly valid on Field.Type == FieldFile.\n",
      "type": "object",
      "properties": {
        "allowed_types": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "cdn": {
          "type": "boolean"
        },
        "chunk_size_mb": {
          "description": "ChunkSizeMB is the client hint for chunked-upload part size (todo",
          "type": "integer"
        },
        "download_cache_ttl": {
          "description": "DownloadCacheTTL is how long a browser may reuse a downloaded file without",
          "type": "string"
        },
        "max_count": {
          "type": "integer"
        },
        "max_download_mb": {
          "description": "MaxDownloadMB caps the size of a file served via download/link routes",
          "type": "integer"
        },
        "max_size_mb": {
          "type": "integer"
        },
        "one_time": {
          "description": "OneTime deletes the object after the configured number of successful",
          "type": "boolean"
        },
        "signed_url_ttl": {
          "description": "e.g. \"15m\"",
          "type": "string"
        },
        "transform": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/StorageTransform"
          }
        },
        "ttl": {
          "description": "TTL auto-deletes the object if it is not downloaded within the",
          "type": "string"
        },
        "visibility": {
          "description": "public | private | signed",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "StorageTransform": {
      "description": "StorageTransform declares an image transformation preset for a file field.\n",
      "type": "object",
      "properties": {
        "fit": {
          "description": "cover | contain | fill",
          "type": "string"
        },
        "height": {
          "type": "integer"
        },
        "name": {
          "type": "string"
        },
        "width": {
          "type": "integer"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "SubDeliveryDecl": {
      "description": "SubDeliveryDecl configures the delivery channel for a subscription (02-core-extended.md §3).\n",
      "type": "object",
      "properties": {
        "channel": {
          "description": "webhook | notification | pubsub | queue",
          "type": "string"
        },
        "header": {
          "description": "header name for url_from: header",
          "type": "string"
        },
        "sign": {
          "type": "boolean"
        },
        "url_from": {
          "description": "header | config",
          "type": "string"
        }
      },
      "required": [
        "channel"
      ],
      "additionalProperties": false
    },
    "SummarySource": {
      "description": "SummarySource describes one durable source entity used to rebuild a summary\nprojection. The concrete join semantics are implementation-defined but the\ncontract is the same across backends: combine these sources by join_key.\nSee docs/spec/backend/02-core-extended.md §6.\n",
      "type": "object",
      "properties": {
        "alias": {
          "type": "string"
        },
        "entity": {
          "type": "string"
        },
        "filter": {
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "TableAction": {
      "description": "TableAction is a clickable action on a table row or bulk selection.\n",
      "type": "object",
      "properties": {
        "action": {
          "type": "string"
        },
        "confirm_msg": {
          "type": "string"
        },
        "icon": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "view": {
          "description": "Navigate to a view resource (`\u003ckind\u003e:\u003cname\u003e`, e.g. `print:receipt-thermal`) instead of running the entity action. The record id is appended for kinds whose route takes one.",
          "type": "string",
          "examples": [
            "print:table-tent-card"
          ]
        }
      },
      "required": [
        "action",
        "label"
      ],
      "additionalProperties": false
    },
    "TableCellFormat": {
      "title": "Table Cell Format",
      "description": "Value formatter for a table/listing cell. Closed set — every name is implemented by the cell renderer.",
      "type": "string",
      "enum": [
        "currency",
        "number",
        "date",
        "relative",
        "percent"
      ]
    },
    "TableCellWidget": {
      "title": "Table Cell Widget",
      "description": "Widget rendering a table or listing cell. Closed set — every name is implemented by the cell renderer; omit to render the raw value (optionally via `format`).",
      "type": "string",
      "enum": [
        "badge",
        "boolean",
        "image",
        "qrcode"
      ]
    },
    "TableColumn": {
      "description": "TableColumn configures a table column.\n",
      "type": "object",
      "properties": {
        "align": {
          "description": "Text alignment of this column's header and body cells.",
          "type": "string",
          "enum": [
            "",
            "left",
            "center",
            "right"
          ]
        },
        "field": {
          "type": "string"
        },
        "format": {
          "$ref": "#/$defs/TableCellFormat",
          "description": "Format is the value formatter for this cell. Closed set — every name is"
        },
        "label": {
          "type": "string"
        },
        "link": {
          "description": "Page name to navigate to when this cell is clicked.",
          "type": "string"
        },
        "sortable": {
          "type": "boolean"
        },
        "widget": {
          "$ref": "#/$defs/TableCellWidget"
        },
        "width": {
          "description": "CSS width for this column, applied to the header cell (e.g. \\\"120px\\\", \\\"10rem\\\").",
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "TimelineDisplay": {
      "description": "TimelineDisplay maps entity fields to timeline card slots.\n",
      "type": "object",
      "properties": {
        "component": {
          "type": "string"
        },
        "content_field": {
          "type": "string"
        },
        "icon_field": {
          "type": "string"
        },
        "subtitle_field": {
          "type": "string"
        },
        "title_field": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "TransitionDecl": {
      "description": "TransitionDecl defines a transition between states (Core §14).\nThe canonical manifest key for the triggering action is `via`;\n`action` is accepted as a legacy alias.\n",
      "type": "object",
      "properties": {
        "approval": {
          "$ref": "#/$defs/ApprovalSpec",
          "description": "Approval gates this transition behind an approval chain (02-core-extended.md",
          "nullable": true
        },
        "audit": {
          "description": "Audit records this transition in the business audit trail. Meaningful only",
          "type": "boolean"
        },
        "conditions": {
          "description": "Conditions gate the transition ACTION before it runs (e.g. a required",
          "type": "array",
          "items": {
            "$ref": "#/$defs/ConditionDecl"
          }
        },
        "description": {
          "description": "Deskripsi transisi; dipakai sebagai label tombol bila `ui.button_label` tidak ada.",
          "type": "string",
          "examples": [
            "Semua pesanan meja sudah disajikan"
          ]
        },
        "emit": {
          "description": "Emit names the event this transition publishes when it fires (S13). It",
          "type": "string"
        },
        "emits": {
          "description": "Emits publishes an event when this transition fires. Distinct from",
          "type": "string"
        },
        "expose": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "from": {
          "oneOf": [
            {
              "description": "Single source state name",
              "type": "string"
            },
            {
              "description": "List of source state names",
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ]
        },
        "guard": {
          "$ref": "#/$defs/GuardDecl",
          "nullable": true
        },
        "idempotency_key": {
          "$ref": "#/$defs/IdempotencyDecl",
          "nullable": true
        },
        "idempotent": {
          "description": "Idempotent / IdempotencyKey apply to a transition that has an `impl` and",
          "type": "boolean"
        },
        "impl": {
          "$ref": "#/$defs/ImplDecl",
          "description": "Impl makes this transition an ACTION WITH A ROUTE, exactly like a declared",
          "nullable": true
        },
        "params": {
          "$ref": "#/$defs/ParamsDecl",
          "nullable": true
        },
        "rate_limit": {
          "$ref": "#/$defs/RateLimitSpec",
          "nullable": true
        },
        "require_permission": {
          "description": "Permission the caller must hold to run this transition (own-module prefix may be omitted — same convention as Action.required_permission).",
          "type": "string",
          "examples": [
            "dining-tables.release"
          ]
        },
        "to": {
          "type": "string"
        },
        "ui": {
          "$ref": "#/$defs/ActionUIHint",
          "description": "UI carries the button hints for this transition (label, style, icon,",
          "nullable": true
        },
        "uses": {
          "$ref": "#/$defs/UsesDecl",
          "description": "Uses / Params / Expose / RateLimit complete the \"via is a full action\"",
          "nullable": true
        },
        "via": {
          "type": "string"
        }
      },
      "required": [
        "to",
        "via"
      ],
      "additionalProperties": false
    },
    "UnitDecl": {
      "description": "UnitDecl declares the unit dimension of a field (S12): `Base` is the unit\nvalues are stored in, `Convertible` lists the units callers may convert\nto/from. Both are validated against the field's enum values, so a typo cannot\nsilently disable conversion.\n",
      "type": "object",
      "properties": {
        "base": {
          "description": "Base (storage) unit, e.g. gram",
          "type": "string",
          "minLength": 1
        },
        "convertible": {
          "description": "Units convertible to/from the base unit",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "factors": {
          "description": "Factors maps each convertible unit to how many base units one of it is",
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "base"
      ],
      "additionalProperties": false
    },
    "UsesConfigDecl": {
      "description": "UsesConfigDecl specifies config access.\n",
      "type": "object",
      "properties": {
        "read": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "write": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "UsesDbDecl": {
      "description": "UsesDbDecl specifies raw database access per category/module (§11.2).\nDefaults to own module; cross-module write is high-risk consent (D46).\n",
      "type": "object",
      "properties": {
        "read": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "write": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "UsesDecl": {
      "description": "UsesDecl declares what resources/primitives/config an action needs (§11.2).\n",
      "type": "object",
      "properties": {
        "config": {
          "$ref": "#/$defs/UsesConfigDecl",
          "nullable": true
        },
        "datastores": {
          "description": "primitive → datastore name binding",
          "type": "object",
          "additionalProperties": {}
        },
        "db": {
          "$ref": "#/$defs/UsesDbDecl",
          "nullable": true
        },
        "kvstore": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/KvstoreUseDecl"
          }
        },
        "primitives": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "resources": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "secrets": {
          "description": "1.4.2 ctx.secrets access keys (02-core-extended.md §18)",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "ValidationRule": {
      "description": "Validation constraint. Supports 4 YAML formats: string (\\\"required\\\"), colon (\\\"after:end_date\\\"), map-shorthand ({min_length: 1}), or full ({name: \\\"min_length\\\", value: 1})",
      "oneOf": [
        {
          "description": "Shorthand rule name — e.g. \"required\", \"positive\", \"past\"",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "name": {
              "description": "Validation rule name",
              "type": "string"
            },
            "value": {
              "description": "Validation rule value (optional)"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "additionalProperties": {
            "description": "Rule value — string, number, or boolean"
          },
          "minProperties": 1,
          "maxProperties": 1
        }
      ]
    },
    "WebhookAuth": {
      "description": "WebhookAuth declares how inbound webhook payloads are verified.\nstrategy: signature | token\n",
      "type": "object",
      "properties": {
        "signature": {
          "$ref": "#/$defs/WebhookSigConfig",
          "nullable": true
        },
        "strategy": {
          "description": "signature | token",
          "type": "string"
        },
        "token": {
          "$ref": "#/$defs/WebhookTokenConfig",
          "description": "Token configures static-token verification (strategy: token). The token",
          "nullable": true
        }
      },
      "required": [
        "strategy"
      ],
      "additionalProperties": false
    },
    "WebhookDeliveryDecl": {
      "description": "WebhookDeliveryDecl declares where a `webhook` delivery entry posts the event.\n\nUNSIGNED, deliberately, for this first version: there is no HMAC signature and\nno subscriber registry. The endpoint is declared where the consequence is —\n`url:` literally, or `url_from: {config: \u003ckey\u003e}` when the address belongs to\ndeployment config rather than to the module. Signing needs a per-subscriber\nsecret store, which is a separate decision (todo 7.7.6); until then a signed\nentry would be a promise the runtime cannot keep.\n",
      "type": "object",
      "properties": {
        "headers": {
          "description": "Headers are extra request headers (e.g. a routing key). Values may contain",
          "type": "object",
          "additionalProperties": {}
        },
        "url": {
          "description": "URL is the endpoint, literal. Use `url_from` when the address is",
          "type": "string",
          "examples": [
            "https://example.com/hooks/order-paid"
          ]
        },
        "url_from": {
          "$ref": "#/$defs/WebhookURLRef",
          "description": "URLFrom resolves the endpoint from a Config key instead of a literal.",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "WebhookKeyRef": {
      "description": "WebhookKeyRef references the secret key via config.\n",
      "type": "object",
      "properties": {
        "config": {
          "type": "string"
        },
        "secret": {
          "type": "boolean"
        }
      },
      "required": [
        "config"
      ],
      "additionalProperties": false
    },
    "WebhookSigConfig": {
      "description": "WebhookSigConfig configures HMAC signature verification.\n",
      "type": "object",
      "properties": {
        "algorithm": {
          "description": "e.g. hmac-sha512",
          "type": "string"
        },
        "header": {
          "description": "signature header name",
          "type": "string"
        },
        "key": {
          "$ref": "#/$defs/WebhookKeyRef",
          "description": "config reference for the secret key",
          "nullable": true
        },
        "payload": {
          "description": "raw_body | parsed",
          "type": "string"
        }
      },
      "required": [
        "algorithm",
        "header",
        "key"
      ],
      "additionalProperties": false
    },
    "WebhookTokenConfig": {
      "description": "WebhookTokenConfig configures static-token verification for simple internal\nwebhooks (02-core-extended.md §4). The token is referenced via config so it\nnever appears inline in the manifest.\n",
      "type": "object",
      "properties": {
        "header": {
          "description": "Header is the request header carrying the token (e.g. \"Authorization\").",
          "type": "string"
        },
        "key": {
          "$ref": "#/$defs/WebhookKeyRef",
          "description": "Key references the config key holding the expected token value.",
          "nullable": true
        }
      },
      "required": [
        "header",
        "key"
      ],
      "additionalProperties": false
    },
    "WebhookURLRef": {
      "description": "WebhookURLRef resolves a webhook endpoint from a Config key.\n",
      "type": "object",
      "properties": {
        "config": {
          "description": "@schema {example: \"billing.webhook_url\"}",
          "type": "string",
          "examples": [
            "billing.webhook_url"
          ]
        }
      },
      "required": [
        "config"
      ],
      "additionalProperties": false
    },
    "WidgetLayout": {
      "description": "WidgetLayout controls grid placement.\n",
      "type": "object",
      "properties": {
        "h": {
          "type": "integer"
        },
        "w": {
          "type": "integer"
        },
        "x": {
          "type": "integer"
        },
        "y": {
          "type": "integer"
        }
      },
      "required": [
        "x",
        "y",
        "w",
        "h"
      ],
      "additionalProperties": false
    },
    "WizardOnComplete": {
      "description": "WizardOnComplete controls what happens after a successful final submit.\n",
      "type": "object",
      "properties": {
        "banner": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/WizardSummaryItem"
          }
        },
        "redirect": {
          "type": "string"
        },
        "restart": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "WizardStep": {
      "description": "WizardStep is one step in a multi-step wizard.\n",
      "type": "object",
      "properties": {
        "allow_create": {
          "type": "boolean"
        },
        "component": {
          "type": "string"
        },
        "depends_on": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "entity": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FormField"
          }
        },
        "form": {
          "type": "string"
        },
        "layout": {
          "description": "search_select | ...",
          "type": "string"
        },
        "on_enter": {
          "description": "fires when the step becomes active",
          "type": "string"
        },
        "on_next": {
          "description": "fires on Next, before advancing",
          "type": "string"
        },
        "on_prev": {
          "description": "fires on Previous, before going back",
          "type": "string"
        },
        "required": {
          "description": "fields that gate the Next button",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "search_fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "summary": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/WizardSummaryItem"
          }
        },
        "title": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    },
    "WizardSummaryItem": {
      "description": "WizardSummaryItem is one line on a wizard confirmation step.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "label": {
          "type": "string"
        }
      },
      "required": [
        "label",
        "field"
      ],
      "additionalProperties": false
    }
  },
  "definitions": {
    "AccessPermission": {
      "description": "Access permission level",
      "type": "string",
      "enum": [
        "read",
        "write",
        "read_write"
      ]
    },
    "Action": {
      "description": "Action defines an operation on an Entity or Service.\n",
      "type": "object",
      "properties": {
        "audit": {
          "type": "boolean"
        },
        "call": {
          "description": "sync (default) | async (§11.4)",
          "type": "string"
        },
        "callback": {
          "$ref": "#/$defs/CallbackDecl",
          "description": "§13.1: callback webhook delivery for tracked async jobs",
          "nullable": true
        },
        "challenge": {
          "description": "Challenge opts this action into its App's anonymous-intake",
          "type": "boolean"
        },
        "conditions": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ConditionDecl"
          }
        },
        "description": {
          "type": "string"
        },
        "disabled": {
          "description": "§11.1 — removes a standard action from every surface",
          "type": "boolean"
        },
        "emits": {
          "description": "event name linked per §12",
          "type": "string"
        },
        "expose": {
          "description": "per-action protocol filter: rest | grpc | ws",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "idempotency_key": {
          "$ref": "#/$defs/IdempotencyDecl",
          "nullable": true
        },
        "idempotent": {
          "type": "boolean"
        },
        "impl": {
          "$ref": "#/$defs/ImplDecl",
          "nullable": true
        },
        "name": {
          "type": "string"
        },
        "params": {
          "$ref": "#/$defs/ParamsDecl",
          "nullable": true
        },
        "public": {
          "description": "Public makes a SERVICE action callable by anonymous callers on the UI",
          "type": "boolean"
        },
        "rate_limit": {
          "$ref": "#/$defs/RateLimitSpec",
          "description": "1.4.1 per-action override (02-core-extended.md §17)",
          "nullable": true
        },
        "required_permission": {
          "description": "RequiredPermission is the permission a caller must hold. For a Service",
          "type": "string"
        },
        "track": {
          "description": "§13: call:async + track:true = tracked async job (job_id + progress)",
          "type": "boolean"
        },
        "ui": {
          "$ref": "#/$defs/ActionUIHint",
          "description": "Backend §5.1 — button rendering hints (confirm, icon, style, etc.)",
          "nullable": true
        },
        "uses": {
          "$ref": "#/$defs/UsesDecl",
          "nullable": true
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "ActionUIHint": {
      "description": "ActionUIHint carries frontend rendering hints for an action button (Backend §5.1).\n",
      "type": "object",
      "properties": {
        "button_label": {
          "type": "string"
        },
        "confirm": {
          "type": "string"
        },
        "icon": {
          "type": "string"
        },
        "show_when": {
          "description": "FormSpecExpr — condition to show this action button",
          "type": "string"
        },
        "style": {
          "description": "Button style variant",
          "type": "string",
          "enum": [
            "primary",
            "secondary",
            "danger"
          ]
        }
      },
      "additionalProperties": false
    },
    "AiIndexDecl": {
      "description": "AiIndexDecl is the optional AI discovery index on a Module\n(ai/04-formspec-remote-mcp.md §3). skills_for_ai is untrusted third-party input.\n",
      "type": "object",
      "properties": {
        "aliases": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "category": {
          "type": "string"
        },
        "features": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "integration_pattern": {
          "type": "string"
        },
        "skills_for_ai": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ApiGRPCConfig": {
      "description": "ApiGRPCConfig configures the gRPC external surface.\n",
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "package": {
          "type": "string"
        }
      },
      "required": [
        "enabled"
      ],
      "additionalProperties": false
    },
    "ApiRESTConfig": {
      "description": "ApiRESTConfig configures the REST external surface.\n",
      "type": "object",
      "properties": {
        "base_path": {
          "description": "@schema {example: \"/invoices\"}",
          "type": "string",
          "examples": [
            "/invoices"
          ]
        },
        "disable": {
          "description": "entities to opt-out",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "version": {
          "description": "@schema {example: \"v2\"}",
          "type": "string",
          "examples": [
            "v2"
          ]
        }
      },
      "additionalProperties": false
    },
    "AppAccess": {
      "description": "AppAccess controls whether an App's surface is publicly reachable without\nauthentication (frontend/05-app-kinds.md §1). `private` is the\nsecure-by-default. Orthogonal to the App renderer archetype: any of\nsidebar-nav/topnav/no-nav may be public or private.\n",
      "type": "string",
      "enum": [
        "private",
        "public"
      ]
    },
    "AppAuth": {
      "description": "AppAuth overrides the auth screens and chrome auth area for one App\n(plan docs_internal/plan/auth-screens-spec-driven.md). Each page slot is a\n`kind: Page` reference in `module/name` form; empty slots fall back to the\nframework's default auth page specs (module formspec.core). ChromeAuth is a\ncomponent asset reference replacing the default auth area (Sign in/Sign up/\nlogout/user menu).\n",
      "type": "object",
      "properties": {
        "change_password_page": {
          "description": "kind: Page ref (module/name) used for change-password — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/change-password"
          ]
        },
        "chrome_auth": {
          "description": "Component asset ref replacing the default chrome auth area — empty = default AuthArea driven by chrome.auth",
          "type": "string",
          "examples": [
            "portal/components/auth-area"
          ]
        },
        "login_page": {
          "description": "kind: Page ref (module/name) used as the login screen — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/login"
          ]
        },
        "oauth_callback_page": {
          "description": "kind: Page ref (module/name) used for the OAuth callback — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/oauth-callback"
          ]
        },
        "reset_password_page": {
          "description": "kind: Page ref (module/name) used for reset-password — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/reset-password"
          ]
        },
        "setup_page": {
          "description": "kind: Page ref (module/name) used as the first-run setup wizard — empty = formspec.core default",
          "type": "string",
          "examples": [
            "portal/pages/setup"
          ]
        }
      },
      "additionalProperties": false
    },
    "AppChrome": {
      "description": "AppChrome fine-tunes which chrome elements the App shell renders\n(frontend/05-app-kinds.md §4.1). Orthogonal to AppRenderer (layout\narchetype) and Access (auth axis): every element defaults to \"auto\" —\nthe archetype's own default — and explicit values override it. The meta\nAPI resolves the effective composition (internal/ui resolveChrome) so\nrenderers read final values.\n",
      "type": "object",
      "properties": {
        "auth": {
          "description": "Auth controls. \"links\": Sign in link + Sign up button (anon) /",
          "type": "string",
          "enum": [
            "auto",
            "links",
            "button",
            "none"
          ],
          "examples": [
            "auto"
          ]
        },
        "brand": {
          "description": "Brand bar — App title + logo.",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        },
        "breadcrumbs": {
          "description": "Breadcrumb row (sidebar-nav/topnav).",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        },
        "footer": {
          "description": "Page footer.",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        },
        "nav": {
          "description": "Navigation links derived from the resolved App menu.",
          "type": "string",
          "enum": [
            "auto",
            "menu",
            "none"
          ],
          "examples": [
            "auto"
          ]
        },
        "profile_route": {
          "description": "ProfileRoute is the in-app route to the signed-in user's profile",
          "type": "string"
        },
        "regions": {
          "description": "Chrome regions — topbar/sidebar/rightbar/bottombar/footer → none | auto | \u003ccomponent-ref\u003e",
          "type": "object",
          "additionalProperties": {},
          "examples": [
            "sidebar: auto"
          ]
        },
        "theme_switcher": {
          "description": "Theme switcher control (sidebar-nav/topnav).",
          "type": "string",
          "enum": [
            "auto",
            "show",
            "hide"
          ],
          "examples": [
            "auto"
          ]
        }
      },
      "additionalProperties": false
    },
    "AppConfirm": {
      "description": "AppConfirm is the App-wide default confirm-dialog configuration\n(plan confirm-dialogs.md). Each verb holds the dialog message; nil =\ninherit/off, \"\" = explicitly off (opt out of an inherited default).\n",
      "type": "object",
      "properties": {
        "create": {
          "description": "Confirm message before create — absent = off; {name} interpolates the entity display name",
          "type": "string",
          "examples": [
            "Buat data baru?"
          ],
          "nullable": true
        },
        "delete": {
          "description": "Confirm message before delete — absent = off; {name} interpolates the entity display name",
          "type": "string",
          "examples": [
            "Hapus data ini?"
          ],
          "nullable": true
        },
        "update": {
          "description": "Confirm message before update — absent = off; {name} interpolates the entity display name",
          "type": "string",
          "examples": [
            "Simpan perubahan?"
          ],
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "AppConsume": {
      "description": "AppConsume is one cross-app interface an App depends on; it triggers a\ngrant request to the owning App (02-workspace-app-module.md §3).\n",
      "type": "object",
      "properties": {
        "actions": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "app": {
          "type": "string"
        },
        "service": {
          "type": "string"
        }
      },
      "required": [
        "app",
        "service"
      ],
      "additionalProperties": false
    },
    "AppInterface": {
      "description": "AppInterface is one cross-app service interface offered by an App\n(02-workspace-app-module.md §3).\n",
      "type": "object",
      "properties": {
        "actions": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "service": {
          "type": "string"
        }
      },
      "required": [
        "service"
      ],
      "additionalProperties": false
    },
    "ApprovalReject": {
      "description": "ApprovalReject declares the target state when the workflow is rejected.\n",
      "type": "object",
      "properties": {
        "to": {
          "type": "string"
        }
      },
      "required": [
        "to"
      ],
      "additionalProperties": false
    },
    "ApprovalSpec": {
      "description": "ApprovalSpec declares the approval gate on a state-machine transition\n(02-core-extended.md §2). It replaces the former `kind: Workflow` manifest:\nthe gate lives ON the transition it intercepts, so the declaration cannot\ndrift from the thing it gates, and a transition with several origin states is\ncovered by construction rather than by a reference kept in step by hand.\n\nIt is declared as `state_machine.transitions[].approval`.\n",
      "type": "object",
      "properties": {
        "on_reject": {
          "$ref": "#/$defs/ApprovalReject",
          "description": "OnReject declares the state the record moves to when the chain is",
          "nullable": true
        },
        "steps": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ApprovalStep"
          }
        }
      },
      "additionalProperties": false
    },
    "ApprovalStep": {
      "description": "ApprovalStep is one approval step in the approval chain.\nSteps are evaluated sequentially; each must reach quorum before the next begins.\n",
      "type": "object",
      "properties": {
        "approvers": {
          "description": "quorum, default 1",
          "type": "integer"
        },
        "description": {
          "description": "Description explains what to check before deciding (S15).",
          "type": "string"
        },
        "display_fields": {
          "description": "DisplayFields names the record fields the approver needs to see to decide",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "escalation": {
          "$ref": "#/$defs/StepEscalation",
          "nullable": true
        },
        "mode": {
          "$ref": "#/$defs/ApprovalStepMode",
          "description": "all | any | sequential"
        },
        "name": {
          "description": "Name identifies the step, so state about a workflow in flight can point at",
          "type": "string",
          "examples": [
            "supervisor-check"
          ],
          "pattern": "^[a-z][a-z0-9-]*$"
        },
        "permission": {
          "description": "Permission is the DUTY this step requires — the `resource + action` form",
          "type": "string",
          "examples": [
            "approve-void"
          ]
        },
        "roles": {
          "description": "Roles lists the roles eligible to sign — who, by NAME.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[gl.supervisor]"
          ]
        },
        "title": {
          "description": "Title is the human label for this approval task (S15). Without it the",
          "type": "string"
        },
        "when": {
          "description": "FormSpecExpr — skip step if false",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ApprovalStepMode": {
      "title": "Workflow Step Mode",
      "description": "How a step's quorum is collected. Closed set. `all` is refused at validate — use `any` with `approvers: N`, or `sequential`.",
      "type": "string",
      "enum": [
        "all",
        "any",
        "sequential"
      ]
    },
    "AssignmentDecl": {
      "description": "AssignmentDecl declares that an entity records a principal→dimension mapping\n(S5): a row of this entity links the principal identified by `PrincipalField`\nto the dimension value held in `Field`. The server resolves `from: session`\nrow-scope attributes from these declarations.\n",
      "type": "object",
      "properties": {
        "dimension": {
          "description": "Scope dimension this assignment provides a value for",
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "field": {
          "description": "Field on this entity holding the dimension value",
          "type": "string"
        },
        "principal_field": {
          "description": "Field on this entity identifying the principal; matched against the authenticated username",
          "type": "string",
          "examples": [
            "username"
          ]
        }
      },
      "required": [
        "dimension",
        "field",
        "principal_field"
      ],
      "additionalProperties": false
    },
    "AuthSettings": {
      "description": "AuthSettings configures external authentication (OAuth/OIDC) providers\n(auth redesign Fase 5). Providers are declared by name under\n`settings.auth.providers`; well-known presets (google, github, microsoft)\nfill in the endpoint URLs, custom providers declare them explicitly.\n",
      "type": "object",
      "properties": {
        "providers": {
          "description": "Providers maps a provider name → its OAuth config. The name is used in",
          "type": "object",
          "additionalProperties": {}
        }
      },
      "additionalProperties": false
    },
    "AutoFillDecl": {
      "description": "AutoFillDecl defines a client-side lookup/auto-fill on a field.\nWhen the relation field named in `from` (same child row) changes, the\nrelated record is fetched and its `field` value is copied into the field\nthat declares this AutoFillDecl.\n",
      "type": "object",
      "properties": {
        "field": {
          "description": "Field — name of the field on the related entity to copy from.",
          "type": "string"
        },
        "from": {
          "description": "From — name of the relation field in the same row that triggers the fill.",
          "type": "string"
        }
      },
      "required": [
        "from",
        "field"
      ],
      "additionalProperties": false
    },
    "BackdatePolicy": {
      "description": "BackdatePolicy controls how far back a transaction_date can be set (§14a).\n",
      "type": "object",
      "properties": {
        "max_days_back": {
          "type": "integer"
        },
        "override_permission": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "BlockBinds": {
      "description": "BlockBinds ties a detail block to the master list block that drives it in a\n`layout.mode: split` page (frontend/06-page-kinds.md §1.1).\n",
      "type": "object",
      "properties": {
        "param": {
          "description": "Param is the field of the selected master record injected into the",
          "type": "string"
        },
        "source": {
          "description": "Source is the `ref` of the master Table block whose row selection",
          "type": "string"
        }
      },
      "required": [
        "source",
        "param"
      ],
      "additionalProperties": false
    },
    "BlockRef": {
      "description": "BlockRef references another resource within a page block.\nEntity is resolved from the referenced Form/Table manifest's `spec.entity` —\nnot declared inline here (removed as redundant, since every Form/Table has\na 1:1 mapping to an entity).\n",
      "type": "object",
      "properties": {
        "asset": {
          "description": "component blocks (§7)",
          "type": "string"
        },
        "binds": {
          "$ref": "#/$defs/BlockBinds",
          "description": "Binds links a detail block to a master list block in a split layout",
          "nullable": true
        },
        "id": {
          "type": "string"
        },
        "mode": {
          "description": "view | edit",
          "type": "string"
        },
        "param": {
          "type": "object",
          "additionalProperties": {}
        },
        "props": {
          "description": "component blocks",
          "type": "object",
          "additionalProperties": {}
        },
        "ref": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "CacheSpec": {
      "description": "CacheSpec configures the framework read-through cache for find-by-id\n(Fase 14). TTL must parse as a Go duration (\"300s\", \"5m\") within 1s–1h.\n",
      "type": "object",
      "properties": {
        "ttl": {
          "description": "@schema {example: \"300s\"}",
          "type": "string",
          "examples": [
            "300s"
          ]
        }
      },
      "required": [
        "ttl"
      ],
      "additionalProperties": false
    },
    "CallbackDecl": {
      "description": "CallbackDecl configures callback webhook delivery for a tracked async job\n(02-core-extended.md §13.1, todo 7.13.4). The callback URL is supplied by\nthe caller via a request header; the result is delivered HMAC-signed.\n",
      "type": "object",
      "properties": {
        "channel": {
          "description": "webhook",
          "type": "string"
        },
        "header": {
          "description": "header carrying the callback URL (e.g. X-Callback-URL)",
          "type": "string"
        },
        "retry": {
          "$ref": "#/$defs/RetryDecl",
          "nullable": true
        },
        "sign": {
          "type": "boolean"
        },
        "url_from": {
          "description": "header",
          "type": "string"
        }
      },
      "required": [
        "channel"
      ],
      "additionalProperties": false
    },
    "Characteristic": {
      "title": "Characteristic",
      "description": "Data nature classification — determines storage strategy, partitioning, and API behavior",
      "type": "string",
      "enum": [
        "master",
        "transaction",
        "reference",
        "summary"
      ],
      "examples": [
        "transaction"
      ]
    },
    "ChildDecl": {
      "description": "ChildDecl defines a child relationship.\n",
      "type": "object",
      "properties": {
        "entity": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Field"
          }
        },
        "picker": {
          "$ref": "#/$defs/PickerDecl",
          "description": "Picker fills this child field by choosing records from another entity",
          "nullable": true
        },
        "sequence_field": {
          "type": "string"
        },
        "storage": {
          "description": "\"jsonb\" or \"table\"",
          "type": "string"
        }
      },
      "required": [
        "storage"
      ],
      "additionalProperties": false
    },
    "ComputedDecl": {
      "description": "ComputedDecl defines a computed/derived field.\n",
      "type": "object",
      "properties": {
        "formula": {
          "type": "string"
        }
      },
      "required": [
        "formula"
      ],
      "additionalProperties": false
    },
    "ConditionDecl": {
      "description": "ConditionDecl is a guard condition for an action (§13 level 3).\nThe canonical manifest form is {script, message}; {field, expression}\nis an older equivalent kept for backward compatibility.\n",
      "type": "object",
      "properties": {
        "expression": {
          "type": "string"
        },
        "field": {
          "type": "string"
        },
        "message": {
          "type": "string"
        },
        "script": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "ConfigKey": {
      "description": "ConfigKey declares one configuration entry (01-core-basic.md §10).\n",
      "type": "object",
      "properties": {
        "default": {},
        "public": {
          "description": "Public opts the key in to UI-surface exposure (plan",
          "type": "boolean"
        },
        "secret": {
          "type": "boolean"
        },
        "type": {
          "description": "int | string | bool | decimal | json",
          "type": "string"
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "ContextDecl": {
      "description": "ContextDecl declares one render-context variable injected into a Page/Form\n(render-context-standard plan). Sources are a closed set:\n\n\tsession | entity | api | const | expr\n\nStandard slots (`user`, `route`, `fields`) are always present and need no\ndeclaration; `context:` adds named variables resolved from these sources.\n",
      "type": "object",
      "properties": {
        "call": {
          "description": "Call for source: api — \"module.service.action\".",
          "type": "string"
        },
        "config": {
          "description": "Config for source: config — \"\u003cconfig-name\u003e.\u003ckey\u003e\" referencing a",
          "type": "string"
        },
        "entity": {
          "description": "Entity ref for source: entity (\"module.entity\").",
          "type": "string"
        },
        "expr": {
          "description": "Expr for source: expr — a FormSpecExpr string evaluated against the",
          "type": "string"
        },
        "fallback": {
          "description": "Fallback is used while the source is loading or on error."
        },
        "id": {
          "description": "ID for source: entity — a record id, or a template token like",
          "type": "string"
        },
        "name": {
          "description": "Name is the context variable name (e.g. \"vendor\") — referenced in",
          "type": "string"
        },
        "params": {
          "description": "Params for source: api — action params.",
          "type": "object",
          "additionalProperties": {}
        },
        "realtime": {
          "description": "Realtime (source: entity) — subscribe to the entity's events and",
          "type": "boolean"
        },
        "source": {
          "description": "Context source — closed set.",
          "type": "string",
          "enum": [
            "session",
            "entity",
            "api",
            "const",
            "expr"
          ]
        },
        "value": {
          "description": "Value for source: const — a literal value."
        }
      },
      "required": [
        "name",
        "source"
      ],
      "additionalProperties": false
    },
    "CreateScopeSpec": {
      "description": "CreateScopeSpec pins a dimension field on CREATE from a record the payload\nreferences — the write-side counterpart of `row_scope`.\n\n`row_scope` answers \"which rows may this caller READ\". It cannot answer the\nwrite question, because a row that does not exist yet has no stored value to\nfilter: `create` is not row-scoped anywhere in the storage layer (InsertParams\ncarries no predicates). So the only place to state \"the branch of a new order\nis the branch of the table session it belongs to\" is the create path itself.\n\nThe rule is CONDITIONAL on the reference: when the payload carries a value for\nRefField, the dimension field must equal the referenced record's ViaField.\nWhen it does not (a cashier creating a walk-in order with no table session),\nthere is nothing to derive from and the rule does not apply — which is\ndeliberate, so one declaration serves both surfaces without a mode switch.\n\nA MISMATCH IS REJECTED (403), never silently overwritten. Overwriting would\nmake the payload lie about what was stored, and the caller would have no way\nto learn that their input was discarded.\n",
      "type": "object",
      "properties": {
        "field": {
          "description": "Dimension field on THIS entity that the create must pin",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        },
        "from": {
          "description": "Where the expected value comes from at request time. Only `record` is defined: a record the payload references.",
          "type": "string",
          "enum": [
            "record"
          ]
        },
        "ref_field": {
          "description": "Relation field on this entity holding the reference (id or natural key) to the record to read from",
          "type": "string",
          "examples": [
            "table_session_id"
          ]
        },
        "via": {
          "description": "The referenced record's entity, as \\\"\u003cmodule\u003e.\u003centity\u003e\\",
          "type": "string",
          "examples": [
            "cafe-order.table-session"
          ]
        },
        "via_field": {
          "description": "Field on `via` holding the expected value",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        }
      },
      "required": [
        "field",
        "ref_field",
        "via",
        "via_field"
      ],
      "additionalProperties": false
    },
    "CurrencySettings": {
      "description": "CurrencySettings configures the default money currency (05-field-types.md §2).\n",
      "type": "object",
      "properties": {
        "code": {
          "description": "Code is the ISO-4217 currency code (e.g. \"IDR\", \"USD\").",
          "type": "string"
        },
        "decimal_places": {
          "description": "DecimalPlaces is the minor-unit scale of this currency (e.g. IDR=0, USD=2).",
          "type": "integer",
          "nullable": true
        },
        "symbol": {
          "description": "Symbol is the optional display symbol (e.g. \"Rp\", \"$\"). When empty, the",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "DashboardWidget": {
      "description": "DashboardWidget places a widget on a dashboard.\n",
      "type": "object",
      "properties": {
        "config": {
          "type": "object",
          "additionalProperties": {}
        },
        "layout": {
          "$ref": "#/$defs/WidgetLayout"
        },
        "ref": {
          "type": "string"
        }
      },
      "required": [
        "ref",
        "layout"
      ],
      "additionalProperties": false
    },
    "DatastoreAccess": {
      "description": "DatastoreAccess controls who can use this datastore and what they can do.\n",
      "type": "object",
      "properties": {
        "filter": {
          "$ref": "#/$defs/DatastoreAccessFilter",
          "description": "Filter determines which workspaces can access this datastore.",
          "nullable": true
        },
        "permission": {
          "$ref": "#/$defs/DatastorePermission",
          "description": "Permission is the ceiling for operations on this datastore.",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "DatastoreAccessFilter": {
      "description": "DatastoreAccessFilter restricts datastore access to specific workspaces.\nAll fields are optional and combined with AND logic.\n",
      "type": "object",
      "properties": {
        "environment": {
          "description": "Environment restricts to workspaces in the named environment (e.g. \"production\").",
          "type": "string"
        },
        "labels": {
          "description": "Labels restricts to workspaces with all the given labels.",
          "type": "object",
          "additionalProperties": {}
        },
        "workspaces": {
          "description": "Workspaces restricts to a specific list of workspace IDs.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "DatastoreConnection": {
      "description": "DatastoreConnection holds the connection parameters.\n",
      "type": "object",
      "properties": {
        "database": {
          "type": "string"
        },
        "extra": {
          "type": "object",
          "additionalProperties": {}
        },
        "host": {
          "type": "string"
        },
        "lazy": {
          "description": "connect on first use",
          "type": "boolean"
        },
        "pool": {
          "$ref": "#/$defs/DatastorePool",
          "nullable": true
        },
        "port": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "DatastoreDriver": {
      "description": "Backend database/driver technology",
      "type": "string",
      "enum": [
        "sqlite",
        "postgres",
        "valkey",
        "redis",
        "s3",
        "garage",
        "minio",
        "nats",
        "memory",
        "fs"
      ]
    },
    "DatastorePermission": {
      "description": "DatastorePermission defines the operation ceiling for this datastore.\n",
      "type": "object",
      "properties": {
        "default": {
          "$ref": "#/$defs/AccessPermission",
          "description": "Default is the baseline access level. Default: read_write."
        },
        "rules": {
          "description": "Rules provide granular overrides for specific scopes.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/DatastorePermissionRule"
          }
        }
      },
      "additionalProperties": false
    },
    "DatastorePermissionRule": {
      "description": "DatastorePermissionRule overrides the default permission for a scope.\n",
      "type": "object",
      "properties": {
        "access": {
          "$ref": "#/$defs/AccessPermission",
          "description": "Access is the permission level for this scope."
        },
        "scope": {
          "description": "Scope is a glob pattern, e.g. \"store.*\", \"billing.invoice\", \"*.*\".",
          "type": "string"
        }
      },
      "required": [
        "scope",
        "access"
      ],
      "additionalProperties": false
    },
    "DatastorePool": {
      "description": "DatastorePool configures connection pooling.\n",
      "type": "object",
      "properties": {
        "max_idle": {
          "type": "integer"
        },
        "max_lifetime": {
          "description": "e.g. \"1h\", \"30m\"",
          "type": "string"
        },
        "max_open": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "DeliveryDecl": {
      "description": "DeliveryDecl configures what happens when an event fires.\n\nDeprecated: predates the nested event `deliver:` list (Core §12); kept for\nbackward compatibility with manifests using a top-level `deliver:` block.\n",
      "type": "object",
      "properties": {
        "channel": {
          "type": "string"
        },
        "event": {
          "type": "string"
        },
        "reliable_event": {
          "type": "boolean"
        },
        "websocket": {
          "type": "boolean"
        }
      },
      "required": [
        "event"
      ],
      "additionalProperties": false
    },
    "DeliveryTarget": {
      "description": "DeliveryTarget addresses the receiver of an event delivery.\n",
      "type": "object",
      "properties": {
        "action": {
          "type": "string"
        },
        "resource": {
          "description": "reliable_event: \"module.entity\"",
          "type": "string"
        },
        "scope": {
          "description": "websocket: workspace | user | ...",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "Dependency": {
      "description": "Dependency declares a module dependency.\n",
      "type": "object",
      "properties": {
        "module": {
          "type": "string"
        },
        "version": {
          "description": "Version is an optional semver constraint (e.g. \"\u003e=1.0 \u003c2.0\")",
          "type": "string"
        }
      },
      "required": [
        "module"
      ],
      "additionalProperties": false
    },
    "DocStatus": {
      "description": "Document lifecycle state (empty = lifecycle-free)",
      "type": "string",
      "enum": [
        "draft",
        "submitted",
        "cancelled"
      ]
    },
    "EntityAuth": {
      "description": "EntityAuth configures authentication for an entity.\n",
      "type": "object",
      "properties": {
        "required": {
          "type": "boolean"
        },
        "strategies": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "required"
      ],
      "additionalProperties": false
    },
    "EnvironmentMode": {
      "description": "Deployment environment mode",
      "type": "string",
      "enum": [
        "dev",
        "prod"
      ]
    },
    "EnvironmentPlane": {
      "description": "EnvironmentPlane is one resource plane endpoint of an Environment.\n",
      "type": "object",
      "properties": {
        "url": {
          "type": "string"
        }
      },
      "required": [
        "url"
      ],
      "additionalProperties": false
    },
    "ErrorCode": {
      "description": "ErrorCode is a canonical FormSpec error code string.\n",
      "type": "string",
      "enum": [
        "FORMSPEC.DOC.UPDATE_NOT_DRAFT",
        "FORMSPEC.DOC.DELETE_REFERENCED",
        "FORMSPEC.DOC.CANCEL_REFERENCED",
        "FORMSPEC.DOC.SUBMIT_NOT_DRAFT",
        "FORMSPEC.DOC.ALREADY_SUBMITTED",
        "FORMSPEC.DOC.ALREADY_CANCELLED",
        "FORMSPEC.DOC.RESERVED_FIELD",
        "FORMSPEC.DOC.CREATE_SUBMIT_NOT_AVAILABLE",
        "FORMSPEC.TXN.TRANSACTION_DATE_MISSING",
        "FORMSPEC.TXN.BACKDATE_EXCEEDED",
        "FORMSPEC.TXN.FORWARD_DATE_EXCEEDED",
        "FORMSPEC.PERIOD.CLOSED",
        "FORMSPEC.PERIOD.REOPEN_DENIED",
        "FORMSPEC.EVENT.TYPE_MISMATCH",
        "FORMSPEC.EVENT.TYPE_MISSING",
        "FORMSPEC.SAGA.OUTCOME_UNKNOWN",
        "FORMSPEC.SAGA.COMPENSATION_FAILED",
        "FORMSPEC.REF.DELETE_BLOCKED",
        "FORMSPEC.REF.CANCEL_BLOCKED",
        "FORMSPEC.PERSIST.CROSS_CATEGORY",
        "FORMSPEC.ARCHIVE.LOCKED_FOR_DELETION",
        "FORMSPEC.VALIDATE.RESERVED_ACTION_MODIFIED",
        "OBSERVABILITY_METRICS_DISABLED",
        "OBSERVABILITY_DEBUG_FORBIDDEN",
        "LOGS_FILTER_INVALID"
      ]
    },
    "EventChannel": {
      "title": "Event Channel",
      "description": "Delivery channel for an event. `audit_log`/`websocket`/`pubsub`/`reliable_event` are implemented by the delivery pipeline; `queue` is declared by the spec but not yet delivered (todo 7.7.6).",
      "type": "string",
      "enum": [
        "audit_log",
        "websocket",
        "queue",
        "pubsub",
        "reliable_event",
        "notification",
        "webhook"
      ]
    },
    "EventDecl": {
      "description": "EventDecl declares an event an entity can publish (Core §12).\n",
      "type": "object",
      "properties": {
        "deliver": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/EventDeliveryDecl"
          }
        },
        "description": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "payload": {
          "$ref": "#/$defs/PayloadDecl",
          "nullable": true
        },
        "publish": {
          "$ref": "#/$defs/PublishDecl",
          "nullable": true
        },
        "type": {
          "description": "sync | async — auto-derived from name prefix if not explicit",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "EventDeliveryDecl": {
      "description": "EventDeliveryDecl is one delivery target of an event — its \"consequence map\" entry (§12).\n",
      "type": "object",
      "properties": {
        "channel": {
          "$ref": "#/$defs/EventChannel",
          "description": "audit_log | websocket | queue | pubsub | reliable_event"
        },
        "dead_letter": {
          "$ref": "#/$defs/DeliveryTarget",
          "nullable": true
        },
        "handler": {
          "description": "Handler names an optional Service action that also delivers this event",
          "type": "string"
        },
        "idempotency_key": {
          "type": "string"
        },
        "job": {
          "description": "Job names the Service action a `queue` entry runs in the background,",
          "type": "string",
          "examples": [
            "receipt-jobs.generate-receipt"
          ]
        },
        "notification": {
          "$ref": "#/$defs/NotificationDecl",
          "description": "Notification describes what a `notification` entry delivers (todo 7.7.6).",
          "nullable": true
        },
        "retry": {
          "$ref": "#/$defs/RetryDecl",
          "nullable": true
        },
        "target": {
          "$ref": "#/$defs/DeliveryTarget",
          "description": "Target addresses an Entity/Service action for `reliable_event`.",
          "nullable": true
        },
        "webhook": {
          "$ref": "#/$defs/WebhookDeliveryDecl",
          "description": "Webhook describes where a `webhook` entry posts the event (todo 7.7.6).",
          "nullable": true
        }
      },
      "required": [
        "channel"
      ],
      "additionalProperties": false
    },
    "ExposeConfig": {
      "description": "ExposeConfig declares one external protocol surface for an Entity (D49).\nEach entry opts the entity into one protocol type. Without any expose entries,\nthe entity is purely internal (same-process services, Starlark, events only).\n",
      "type": "object",
      "properties": {
        "actions": {
          "description": "REST: list, find, create, update, delete",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "enabled": {
          "description": "for grpc/ws: true = full service",
          "type": "boolean"
        },
        "type": {
          "$ref": "#/$defs/ProtocolType",
          "description": "rest | grpc | ws"
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "ExtendStorage": {
      "description": "ExtendStorage declares that this Entity extends another entity's storage\nby adding a new JSONB column (namespace-isolated) to the target table.\n\ntarget:  \"module/entity\" of the base entity being extended\nnamespace:  unique identifier for this extension column (ext_{namespace})\n\nExtension fields MUST NOT be required (required=true is rejected at validation).\nExtension data is stored in a separate column ext_{namespace}, not in the base data JSONB.\nThis allows clean uninstall via DROP COLUMN without affecting base data.\n",
      "type": "object",
      "properties": {
        "namespace": {
          "type": "string"
        },
        "target": {
          "type": "string"
        },
        "validate": {
          "description": "Validate is an additive business rule (4.3.5): a Starlark script ref",
          "type": "string"
        }
      },
      "required": [
        "target",
        "namespace"
      ],
      "additionalProperties": false
    },
    "Field": {
      "description": "Field defines a data field on an Entity.\n@schema {title: \"Field Definition\"}\n",
      "type": "object",
      "properties": {
        "accept_data_loss": {
          "description": "AcceptDataLoss consents to a lossy type change (01-core-basic.md §4.2):",
          "type": "boolean"
        },
        "audited": {
          "type": "boolean"
        },
        "auto_fill": {
          "$ref": "#/$defs/AutoFillDecl",
          "description": "AutoFill — client-side lookup: when the relation field named in `from`",
          "nullable": true
        },
        "child": {
          "$ref": "#/$defs/ChildDecl",
          "nullable": true
        },
        "classification": {
          "$ref": "#/$defs/FieldClassification",
          "description": "1.4.3 FieldClassification — governance label (05-field-types.md §5.4)."
        },
        "computed": {
          "$ref": "#/$defs/ComputedDecl",
          "nullable": true
        },
        "currency": {
          "description": "Money (05-field-types.md §2) — only meaningful for type: money.",
          "type": "string"
        },
        "decimal_places": {
          "type": "integer",
          "nullable": true
        },
        "default": {},
        "description": {
          "description": "Help text shown to users under the input in forms (and wizard steps). Written for the end user — not a design note; it is inherited as the field's `help` wherever the field appears, so one declaration serves both surfaces.",
          "type": "string"
        },
        "encrypted": {
          "description": "1.4.6 EncryptedField — at-rest encryption marker (05-field-types.md §5.2).",
          "type": "boolean"
        },
        "enum_values": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "exclude": {
          "description": "1.4.5 FieldExclude — per-surface field exclusion (05-field-types.md §5.3).",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "immutable": {
          "type": "boolean"
        },
        "index": {
          "type": "boolean"
        },
        "masked": {
          "description": "1.4.7 MaskedField — auto-mask in response/log (05-field-types.md §5.2).",
          "type": "boolean"
        },
        "multiple": {
          "description": "How many of the declared `options` this field holds: `true` = a set (array / comma-separated list), `false` = one value. Required when `options` is declared on `json` or `string`, because those types can hold either shape.",
          "type": "boolean",
          "nullable": true
        },
        "name": {
          "description": "Field name — lowercase snake_case, unique within entity",
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "natural_key": {
          "description": "NaturalKey marks the field as the record's business identifier.",
          "type": "boolean"
        },
        "natural_key_entry": {
          "$ref": "#/$defs/NaturalKeyEntry",
          "description": "NaturalKeyEntry states who supplies the key: the engine, a person, or the engine unless a person supplies one (see the NaturalKeyEntry enum)."
        },
        "natural_key_rule": {
          "$ref": "#/$defs/NaturalKeyRuleDecl",
          "nullable": true
        },
        "options": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FieldOption"
          }
        },
        "precision": {
          "description": "Decimal precision/scale (05-field-types.md §1.2) — only meaningful for",
          "type": "integer",
          "nullable": true
        },
        "read_only": {
          "type": "boolean"
        },
        "readonly_when": {
          "type": "string"
        },
        "reason": {
          "description": "Reason states why a destructive declaration is intended (audit trail).",
          "type": "string",
          "examples": [
            "digantikan branch_id pada 2026-09"
          ]
        },
        "relation": {
          "$ref": "#/$defs/RelationDecl",
          "nullable": true
        },
        "removed": {
          "description": "Removed is the tombstone that lets a field be dropped at all (01-core-basic.md",
          "type": "boolean"
        },
        "renamed_from": {
          "description": "4.2.2 RenamedFrom — declares that this field was renamed from the given",
          "type": "string"
        },
        "required": {
          "type": "boolean"
        },
        "required_permission": {
          "description": "1.4.4 FieldPermission — field-level required_permission (05-field-types.md §5.3).",
          "type": "string"
        },
        "required_when": {
          "type": "string"
        },
        "rules": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ValidationRule"
          }
        },
        "scale": {
          "type": "integer",
          "nullable": true
        },
        "storage": {
          "$ref": "#/$defs/StorageSpec",
          "description": "1.4.11 StorageSpec — file field configuration (05-field-types.md §1.3).",
          "nullable": true
        },
        "title": {
          "description": "Caption shown to users in tables, forms, and detail pages; falls back to the humanised field name",
          "type": "string"
        },
        "tree": {
          "description": "1.4.9 TreeDecl — self-referential hierarchy marker (05-field-types.md §4).",
          "type": "boolean"
        },
        "type": {
          "$ref": "#/$defs/FieldType",
          "description": "@schema {description: \"Data type — determines storage class, renderer widget, and validation\"}"
        },
        "unique": {
          "description": "Unique declares a cross-record uniqueness constraint (unique per tenant).",
          "type": "boolean"
        },
        "unit": {
          "$ref": "#/$defs/UnitDecl",
          "description": "Unit (S12) — declares the unit dimension of a field naming/conversion",
          "nullable": true
        },
        "visible_when": {
          "description": "Client-behavior vocabulary (FormSpecExpr, frontend 08-formspec-expr.md).",
          "type": "string"
        }
      },
      "required": [
        "name",
        "type"
      ],
      "additionalProperties": false
    },
    "FieldClassification": {
      "description": "Data sensitivity classification for governance",
      "type": "string",
      "enum": [
        "pii",
        "financial",
        "internal"
      ]
    },
    "FieldOption": {
      "description": "FieldOption is one choice in a field's `options:` list — a closed set of\nvalues **with captions**. It exists because `enum_values` carries values\nonly: a day-of-week set declared as `[1, 2, 3]` renders as \"1, 2, 3\", so the\nauthor either writes a picker whose choices cannot be read, or a free-text\ntag input that accepts `9`.\n\n`options` is a property of the **data** (which values are legal), not of one\nform — the same reason `enum_values` lives on the Entity. A multi-value field\n(`type: json`, or a string holding a comma-separated list) can therefore be\ndeclared once and rendered, filtered, and labelled consistently.\n\n`Value` keeps the scalar's YAML type (`value: 1` stays the number 1 in the\nbundle and in the stored array, matching what the field actually holds);\n`Label` is the caption shown to users, and defaults to the value itself when\nomitted.\n",
      "type": "object",
      "properties": {
        "label": {
          "description": "Caption shown to users. Defaults to the value (humanised) when omitted.",
          "type": "string"
        },
        "value": {
          "description": "Stored value. Keep the scalar type the field stores — `value: 1` for a numeric set, not `value: \\\"1\\\"`."
        }
      },
      "required": [
        "value"
      ],
      "additionalProperties": false
    },
    "FieldRef": {
      "description": "FieldRef references another entity's field.\n",
      "type": "object",
      "properties": {
        "entity": {
          "type": "string"
        },
        "field": {
          "type": "string"
        }
      },
      "required": [
        "entity",
        "field"
      ],
      "additionalProperties": false
    },
    "FieldType": {
      "title": "Field Type",
      "description": "Data type for a field — determines storage class, renderer widget, and validation rules",
      "type": "string",
      "enum": [
        "string",
        "text",
        "richtext",
        "integer",
        "decimal",
        "money",
        "boolean",
        "enum",
        "date",
        "datetime",
        "time",
        "uuid",
        "json",
        "file",
        "attachment",
        "relation",
        "child",
        "percent",
        "number"
      ]
    },
    "FilterSpec": {
      "description": "FilterSpec is a generic filter declaration shared by every data kind that\nlists records (Table, Kanban, Listing, ApprovalInbox, …). A filter is used\nin one of two roles:\n  - `filters`: a user-adjustable control rendered in the kind's UI. If\n    `default` is set, the control is pre-seeded with that value (the user\n    can still change or clear it).\n  - `fixed_filters`: a filter the renderer always merges into the list\n    request — never rendered as a control and not user-clearable *in the UI*.\n    It is NOT an authorization boundary: the merge happens in the browser\n    (renderers/react-shadcn/src/lib/filters.ts), so a client that calls the\n    API directly simply omits it. For a filter the server enforces, use the\n    entity's `row_scope` (EntitySpec.RowScope) instead.\n\nThe resolved value is sent to the list API as `field[op]=value`, so `op`\ndefaults to \"eq\" and follows the backend filter operator set.\n\nA value can also come from the request context instead of the manifest, via\n`from` (S2/#6): `from: session` takes it from an identity attribute named by\n`attr` and is resolved server-side only (a client cannot supply or widen it),\nwhile `from: route` takes it from the query parameter named by `param` (e.g. an\nunguessable guest token, where the token itself is the credential).\n\nWhen `from` is empty the value is the LITERAL in `value`, which is what makes\na server-enforced constant expressible — e.g. a role granted `list` on orders\nbut only for `{field: status, op: in, value: \"paid,in_kitchen\"}`. `default` is\nNOT that literal: it only pre-seeds a user-adjustable control, and the user\n(or any client) can change or clear it.\n",
      "type": "object",
      "properties": {
        "all_label": {
          "description": "For select filters: caption of the \\\"All\\\" (clear) option. Default \\\"(ALL)\\\".",
          "type": "string"
        },
        "attr": {
          "description": "Identity attribute for `from: session`: principal_id | username | workspace | an application attribute.",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        },
        "default": {
          "description": "Pre-set value for a user-adjustable filter. Supports \\\"today\\\" / \\\"today()\\\", resolved by the renderer as the server's current date. NOT a server-enforced constant — use `value` for that.",
          "type": "string"
        },
        "field": {
          "type": "string"
        },
        "from": {
          "description": "Where the value comes from at request time: session (identity attribute in `attr`) or route (query parameter in `param`). Empty = the literal `value`.",
          "type": "string",
          "enum": [
            "session",
            "route"
          ]
        },
        "label": {
          "type": "string"
        },
        "op": {
          "description": "Filter operator sent to the list API",
          "type": "string",
          "enum": [
            "eq",
            "neq",
            "gt",
            "gte",
            "lt",
            "lte",
            "between",
            "in",
            "nin",
            "like",
            "ilike",
            "null",
            "notnull"
          ]
        },
        "param": {
          "description": "Query parameter name for `from: route`. Defaults to the field name.",
          "type": "string",
          "examples": [
            "token"
          ]
        },
        "show_all": {
          "description": "For select filters: show the \\\"All\\\" (clear) option. Default true.",
          "type": "boolean",
          "nullable": true
        },
        "type": {
          "description": "Filter widget type",
          "type": "string",
          "enum": [
            "text",
            "select",
            "date",
            "date_range"
          ]
        },
        "value": {
          "description": "Literal value used when `from` is empty. For `op: in`/`nin`/`between` this may be a comma-separated list, e.g. \\\"paid,in_kitchen\\\".",
          "type": "string",
          "examples": [
            "paid,in_kitchen,ready"
          ]
        },
        "via": {
          "description": "Entity the `param` value references, as \\\"\u003cmodule\u003e.\u003centity\u003e\\\" — the scope value is read from `via_field` of that record.",
          "type": "string",
          "examples": [
            "cafe-order.table-session"
          ]
        },
        "via_field": {
          "description": "Field on `via` holding the scope value (required with `via`).",
          "type": "string",
          "examples": [
            "branch_id"
          ]
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "FormAction": {
      "description": "FormAction is a custom action button on a form (Frontend §4).\n",
      "type": "object",
      "properties": {
        "action": {
          "type": "string"
        },
        "confirm": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "style": {
          "description": "primary | secondary | danger",
          "type": "string"
        }
      },
      "required": [
        "action"
      ],
      "additionalProperties": false
    },
    "FormConfirm": {
      "description": "FormConfirm is the per-form confirm override (plan confirm-dialogs.md).\n",
      "type": "object",
      "properties": {
        "create": {
          "description": "Confirm message before create — nil = inherit App default, empty string = off",
          "type": "string",
          "nullable": true
        },
        "delete": {
          "description": "Confirm message before delete — nil = inherit App default, empty string = off",
          "type": "string",
          "nullable": true
        },
        "update": {
          "description": "Confirm message before update — nil = inherit App default, empty string = off",
          "type": "string",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "FormField": {
      "description": "FormField configures a single field in a form.\nYAML uses `field:` to reference the Entity field name; JSON serializes as\n`name:` to match the TypeScript FormField interface.\n",
      "type": "object",
      "properties": {
        "compute": {
          "type": "string"
        },
        "default_from": {
          "description": "DefaultFrom seeds the field's initial value from the render context: a",
          "type": "string",
          "examples": [
            "{session.branch_id}"
          ]
        },
        "field": {
          "type": "string"
        },
        "help": {
          "description": "Help text shown under the input. Falls back to the entity field's `description`, so declaring it here is only needed to override that per-form.",
          "type": "string"
        },
        "label": {
          "description": "Caption for this field in the form; falls back to the entity field's `title`, then the humanised field name",
          "type": "string"
        },
        "placeholder": {
          "description": "Placeholder text inside the input control",
          "type": "string"
        },
        "read_only": {
          "type": "boolean"
        },
        "readonly_when": {
          "type": "string"
        },
        "required_when": {
          "type": "string"
        },
        "visible_when": {
          "type": "string"
        },
        "widget": {
          "$ref": "#/$defs/FormWidget"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "FormRender": {
      "description": "Render mode: modal (popup dialog), drawer (side panel), separate_page (full page)",
      "type": "string",
      "enum": [
        "modal",
        "drawer",
        "separate_page"
      ]
    },
    "FormRenderDecl": {
      "description": "FormRenderDecl is the design-time container declaration of a Form\n(Frontend §1.6). YAML accepts both `render: separate_page` (shorthand) and\n`render: { mode: separate_page }`; JSON always serializes the object form to\nmatch the renderer contract (`spec.render.mode`).\n",
      "oneOf": [
        {
          "description": "Shorthand render mode — e.g. \"drawer\", \"modal\", \"separate_page\"",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "mode": {
              "$ref": "#/$defs/FormRender",
              "description": "@schema {description: \"Render mode: modal (popup dialog), drawer (side panel), separate_page (full page)\", enum: [\"modal\", \"drawer\", \"separate_page\"]}"
            },
            "picker_panel": {
              "description": "PickerPanel places the child-field picker relative to the rest of the",
              "type": "string",
              "enum": [
                "",
                "inline",
                "aside"
              ]
            }
          },
          "required": [
            "mode"
          ],
          "additionalProperties": false
        }
      ]
    },
    "FormSection": {
      "description": "FormSection groups form fields.\n",
      "type": "object",
      "properties": {
        "columns": {
          "type": "integer"
        },
        "description": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FormField"
          }
        },
        "title": {
          "type": "string"
        },
        "visible_when": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    },
    "FormSubmit": {
      "description": "FormSubmit configures the submit button and post-submit behavior.\n",
      "type": "object",
      "properties": {
        "call": {
          "description": "Call turns the form's submit into a SERVICE call instead of an entity",
          "type": "string",
          "examples": [
            "cafe-order.table-access.open"
          ]
        },
        "label": {
          "type": "string"
        },
        "message": {
          "type": "string"
        },
        "redirect": {
          "description": "Redirect is where a successful submit lands, overriding the derived list",
          "type": "string",
          "examples": [
            "/menu/{response.guest_token}"
          ]
        }
      },
      "additionalProperties": false
    },
    "FormWidget": {
      "title": "Form Widget",
      "description": "Widget rendering a form field. Closed set — every name is implemented by the renderer; omit to use the default derived from the field type.",
      "type": "string",
      "enum": [
        "input",
        "textarea",
        "richtext",
        "number",
        "decimalinput",
        "select",
        "switch",
        "radio-group",
        "combobox",
        "password",
        "slider",
        "tags",
        "select-multi-tag",
        "uuid",
        "json",
        "fileinput",
        "relation-picker",
        "datepicker",
        "datetimeinput",
        "child-grid",
        "grants-editor",
        "hidden",
        "qrcode",
        "moneyinput",
        "timeinput"
      ]
    },
    "ForwardDatePolicy": {
      "description": "ForwardDatePolicy controls how far forward a transaction_date can be set (§14a).\nDefault max_days_forward = 0 (no forward dating allowed).\n",
      "type": "object",
      "properties": {
        "max_days_forward": {
          "type": "integer"
        },
        "override_permission": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "GuardDecl": {
      "description": "GuardDecl is a condition that must be met for a transition.\nYAML accepts either an inline expression string (canonical, Core §14)\nor a map with explicit expression/message keys.\n",
      "oneOf": [
        {
          "description": "Inline guard expression — e.g. \"len(resource.items) \u003e 0 and resource.total \u003e 0\"",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "expression": {
              "type": "string"
            },
            "message": {
              "type": "string"
            }
          },
          "required": [
            "expression"
          ],
          "additionalProperties": false
        }
      ]
    },
    "HookDecl": {
      "description": "HookDecl attaches handler code to an action's before/after/on_error point,\nor an event's before_deliver/after_deliver point (Core Extended §8). A\nreserved action's own Impl (Action.Impl) is equivalent to one hook scoped\nto that action, running last in the before-phase — hooks: entries let\nother modules/scripts attach additional code to the same points, by name\nor via the \"*\" wildcard, with priority ordering (default 10; lower runs\nfirst).\n",
      "type": "object",
      "properties": {
        "action": {
          "description": "action name or \"*\" — before/after/on_error only",
          "type": "string"
        },
        "event": {
          "description": "event name or \"*\" — before_deliver/after_deliver only",
          "type": "string"
        },
        "impl": {
          "$ref": "#/$defs/ImplDecl",
          "nullable": true
        },
        "on": {
          "$ref": "#/$defs/HookTiming"
        },
        "priority": {
          "description": "0 → default 10",
          "type": "integer"
        },
        "uses": {
          "$ref": "#/$defs/UsesDecl",
          "description": "Uses declares the hook script's own access (db, resources, config,",
          "nullable": true
        }
      },
      "required": [
        "on",
        "impl"
      ],
      "additionalProperties": false
    },
    "HookTiming": {
      "description": "When the hook executes relative to the action/event",
      "type": "string",
      "enum": [
        "before",
        "after",
        "on_error",
        "before_deliver",
        "after_deliver"
      ]
    },
    "IdempotencyDecl": {
      "description": "IdempotencyDecl specifies how idempotency keys are derived.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "from": {
          "type": "string"
        }
      },
      "required": [
        "from"
      ],
      "additionalProperties": false
    },
    "ImplDecl": {
      "description": "ImplDecl specifies how an action is implemented.\n",
      "type": "object",
      "properties": {
        "ref": {
          "type": "string"
        },
        "type": {
          "$ref": "#/$defs/ImplType"
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "ImplType": {
      "title": "Implementation Type",
      "description": "How an action is implemented: script_ref (Starlark file), script (inline Starlark), native (Go), compiled (WASM), sidecar (external process)",
      "type": "string",
      "enum": [
        "script_ref",
        "script",
        "native",
        "compiled",
        "sidecar"
      ],
      "examples": [
        "native"
      ]
    },
    "IndexDecl": {
      "description": "IndexDecl declares a database index.\n",
      "type": "object",
      "properties": {
        "fields": {
          "description": "Fields covered by the index; may name relation fields",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "unique": {
          "type": "boolean"
        },
        "where": {
          "description": "Partial index predicate over field names: '\u003cfield\u003e \u003cop\u003e \u003cliteral\u003e' and/or '\u003cfield\u003e IS [NOT] NULL', joined by AND",
          "type": "string",
          "examples": [
            "status = 'open"
          ]
        }
      },
      "additionalProperties": false
    },
    "InputSet": {
      "description": "InputSet is a named, reusable list of inputs declared on the Entity.\n\nTransitions that collect the same parameters share one set through\n`params.inputs_from` instead of repeating the declaration. The set lives on\nthe Entity rather than on an action because a transition's parameters are\ndrawn from the same field pool as the record's — which is also why a \"one\nshared form for every transition\" is not expressible: permission, conditions,\napproval interception, and event emission all attach to individual\ntransitions, not to the entity.\n",
      "type": "object",
      "properties": {
        "inputs": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ParamInput"
          }
        },
        "name": {
          "description": "Set name, referenced by a transition's or action's `params.inputs_from`.",
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*$"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "IntakeChallenge": {
      "description": "IntakeChallenge configures the browser proof-of-work gate.\n",
      "type": "object",
      "properties": {
        "activate_at": {
          "description": "Fraction (0..1) of the global budget that activates the gate (mode: escalate); absent = 0.7, 0 = activate immediately",
          "type": "number",
          "examples": [
            "0.7"
          ],
          "nullable": true
        },
        "bind": {
          "description": "Extra bound attributes (subset of: ip); empty binds only the action",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[ip]"
          ]
        },
        "difficulty": {
          "$ref": "#/$defs/PowDifficulty",
          "description": "Difficulty is the proof-of-work range in leading zero bits of SHA-256.",
          "nullable": true
        },
        "global": {
          "$ref": "#/$defs/RateLimitSpec",
          "description": "Global is the pressure signal: a rate limit measured across ALL anonymous",
          "nullable": true
        },
        "mode": {
          "description": "escalate (default, on only under pressure) | always",
          "type": "string",
          "enum": [
            "escalate",
            "always"
          ],
          "examples": [
            "escalate"
          ]
        },
        "provider": {
          "description": "Challenge mechanism — only \\\"pow\\\" (self-hosted proof-of-work) is implemented",
          "type": "string",
          "enum": [
            "pow"
          ],
          "examples": [
            "pow"
          ]
        },
        "ttl": {
          "description": "Challenge lifetime (Go duration string) — bounds the replay window",
          "type": "string",
          "examples": [
            "90s"
          ]
        }
      },
      "additionalProperties": false
    },
    "IntakeSpec": {
      "description": "IntakeSpec declares protection for an App's ANONYMOUS intake surface — the\nendpoints an unauthenticated caller can reach through this App's derived\npublic grants (plan docs_internal/plan/intake-challenge-pow.md).\n\nAuthored on the App because the App is the reviewed unit of \"what may an\nanonymous caller touch\"; an Action opts in with `challenge: true`, and the\npolicy (how hard, when, how long) lives here so it has one owner. An opt-in\nwith no policy is a validation error rather than a silent no-op.\n\nEnforcement is keyed by (module, entity, action), NOT by App: an anonymous\n`_ui/entity` request carries no App (AppFromContext is empty without an\nidentity, and publicGrants() already merges every public App into a single\nmodule/entity map). Where several public Apps declare a policy the\nSTRICTEST wins — sharing a route must never weaken protection.\n",
      "type": "object",
      "properties": {
        "challenge": {
          "$ref": "#/$defs/IntakeChallenge",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "IntegratorCall": {
      "description": "IntegratorCall declares the target action to invoke.\n",
      "type": "object",
      "properties": {
        "action": {
          "description": "@schema {example: \"create\"}",
          "type": "string",
          "examples": [
            "create"
          ]
        },
        "map": {
          "description": "Map declares how the source event payload becomes the target action's",
          "type": "object",
          "additionalProperties": {}
        },
        "resource": {
          "description": "@schema {example: \"gl.journal-entry\"}",
          "type": "string",
          "examples": [
            "gl.journal-entry"
          ]
        }
      },
      "required": [
        "resource",
        "action"
      ],
      "additionalProperties": false
    },
    "IntegratorListen": {
      "description": "IntegratorListen declares the source event to react to.\n",
      "type": "object",
      "properties": {
        "event": {
          "description": "@schema {example: \"on_submit\"}",
          "type": "string",
          "examples": [
            "on_submit"
          ]
        },
        "resource": {
          "description": "@schema {example: \"sales.order\"}",
          "type": "string",
          "examples": [
            "sales.order"
          ]
        }
      },
      "required": [
        "resource",
        "event"
      ],
      "additionalProperties": false
    },
    "InvariantDecl": {
      "description": "InvariantDecl declares a property a summary projection must satisfy (S14).\nOnly `unique` is defined: it is validated against the declared indexes, so\nthe database — not discipline — keeps the property true.\n",
      "type": "object",
      "properties": {
        "message": {
          "description": "Human-readable statement of the invariant",
          "type": "string"
        },
        "unique": {
          "description": "Columns that must be unique together on this projection",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "KanbanCard": {
      "description": "KanbanCard defines what fields appear on a card.\n",
      "type": "object",
      "properties": {
        "assignee": {
          "type": "string"
        },
        "badge": {
          "type": "string"
        },
        "component": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "subtitle": {
          "type": "string"
        },
        "title": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    },
    "KanbanColumn": {
      "description": "KanbanColumn is a status lane in a kanban board.\n",
      "type": "object",
      "properties": {
        "color": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "status": {
          "type": "string"
        }
      },
      "required": [
        "status",
        "label"
      ],
      "additionalProperties": false
    },
    "Kind": {
      "title": "Resource Kind",
      "description": "Kind represents the resource kind as a PascalCase string.\n@schema {title: \"Resource Kind\"}\n",
      "type": "string",
      "enum": [
        "Seed",
        "App",
        "Module",
        "Entity",
        "Document",
        "Service",
        "Config",
        "Subscription",
        "Api",
        "KindDefinition",
        "Webhook",
        "Mockup",
        "Integrator",
        "Environment",
        "Policy",
        "Datastore",
        "Renderer",
        "VisualSpecKind",
        "PersistBackend",
        "Page",
        "Form",
        "Table",
        "Dashboard",
        "Widget",
        "Report",
        "Wizard",
        "Kanban",
        "Timeline",
        "Print",
        "Theme",
        "Listing",
        "Calendar",
        "ApprovalInbox",
        "NotificationCenter",
        "Workspace"
      ]
    },
    "KvstoreUseDecl": {
      "description": "KvstoreUseDecl specifies durable key-value store access (§11.2).\n",
      "type": "object",
      "properties": {
        "access": {
          "description": "read | read_write",
          "type": "string"
        },
        "module": {
          "type": "string"
        },
        "scope": {
          "description": "workspace | module | global",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "MenuItem": {
      "type": "object",
      "properties": {
        "children": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/MenuItem"
          }
        },
        "icon": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "module": {
          "type": "string"
        },
        "permissions": {
          "description": "RBAC: the item is withheld unless the caller holds at least one of these permissions (any-of). Enforced server-side — it never reaches a caller who lacks them.",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[clinic.settings.update]"
          ]
        },
        "route": {
          "description": "raw URL escape hatch (no registered View)",
          "type": "string"
        },
        "type": {
          "description": "\"module\" = adopt-shorthand node",
          "type": "string"
        },
        "view": {
          "description": "name of a registered View resource",
          "type": "string"
        },
        "when": {
          "description": "FormSpecExpr business condition (presentation only): item hidden when false. Evaluated client-side against `user` and `today()`. NOT an authorization gate — use `permissions` for RBAC.",
          "type": "string",
          "examples": [
            "today() \u003e= '2026-01-01"
          ]
        }
      },
      "additionalProperties": false
    },
    "Metadata": {
      "description": "Metadata is common to all FormSpec resources.\n",
      "type": "object",
      "properties": {
        "annotations": {
          "type": "object",
          "additionalProperties": {}
        },
        "description": {
          "type": "string"
        },
        "labels": {
          "type": "object",
          "additionalProperties": {}
        },
        "module": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "NaturalKeyEntry": {
      "title": "Natural Key Entry",
      "description": "Who supplies the natural key: `auto_generated` (engine only), `user_entry` (a person), `auto_generated_if_empty` (engine mints it unless a value is supplied).",
      "type": "string",
      "enum": [
        "auto_generated",
        "user_entry",
        "auto_generated_if_empty"
      ]
    },
    "NaturalKeyPrefix": {
      "description": "NaturalKeyPrefix defines the prefix for a natural key.\n",
      "type": "object",
      "properties": {
        "config": {
          "type": "string"
        },
        "default": {
          "type": "string"
        },
        "value": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "NaturalKeyRuleDecl": {
      "description": "NaturalKeyRuleDecl defines how a natural key is generated.\n",
      "type": "object",
      "properties": {
        "format": {
          "type": "string"
        },
        "prefix": {
          "$ref": "#/$defs/NaturalKeyPrefix",
          "nullable": true
        },
        "reset": {
          "description": "never | yearly | monthly | daily",
          "type": "string"
        },
        "scope_field": {
          "type": "string"
        },
        "strategy": {
          "description": "sequence | custom",
          "type": "string"
        }
      },
      "required": [
        "strategy"
      ],
      "additionalProperties": false
    },
    "NotificationDecl": {
      "description": "NotificationDecl describes the in-app notification a `notification` delivery\nentry creates.\n\nEvery field is a template over the EVENT PAYLOAD (`{dotted.path}`), because\nthat is what the delivery receives: the publisher declared `payload.fields`,\nso what is available here is exactly that projection — not the record.\n",
      "type": "object",
      "properties": {
        "body": {
          "description": "Body is the notification's text, interpolated from the payload.",
          "type": "string"
        },
        "level": {
          "description": "Level is the notification's severity (info | warning | critical).",
          "type": "string",
          "enum": [
            "info",
            "warning",
            "critical"
          ],
          "examples": [
            "info"
          ]
        },
        "recipient": {
          "description": "Recipient is the payload path whose value becomes the notification's",
          "type": "string",
          "examples": [
            "customer_id"
          ]
        },
        "title": {
          "description": "Title is the notification's heading, interpolated from the payload.",
          "type": "string",
          "examples": [
            "Pesanan {number} dibayar"
          ]
        }
      },
      "required": [
        "recipient",
        "title"
      ],
      "additionalProperties": false
    },
    "OAuthProviderSettings": {
      "description": "OAuthProviderSettings configures one external auth provider.\n\n  - type: \"oidc\" (default) | \"oauth2\". OIDC uses discovery (issuer) to\n    resolve endpoints; oauth2 declares them explicitly.\n  - Presets: name \"google\" | \"github\" | \"microsoft\" fill in the endpoint\n    URLs automatically — only client_id/client_secret are required.\n  - Custom: declare type + authorize_url/token_url/userinfo_url.\n",
      "type": "object",
      "properties": {
        "authorize_url": {
          "description": "AuthorizeURL / TokenURL / UserInfoURL for type: oauth2 (custom).",
          "type": "string"
        },
        "client_id": {
          "description": "OAuth client ID",
          "type": "string"
        },
        "client_secret": {
          "description": "OAuth client secret (secret — never exposed to the renderer)",
          "type": "string"
        },
        "issuer": {
          "description": "Issuer is the OIDC issuer URL (type: oidc) — discovery resolves",
          "type": "string"
        },
        "scopes": {
          "description": "OAuth scopes (default: openid email profile)",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "token_url": {
          "type": "string"
        },
        "type": {
          "description": "@schema {enum: [\"oidc\", \"oauth2\"], default: \"oidc\"}",
          "type": "string",
          "enum": [
            "oidc",
            "oauth2"
          ]
        },
        "userinfo_url": {
          "type": "string"
        }
      },
      "required": [
        "client_id",
        "client_secret"
      ],
      "additionalProperties": false
    },
    "OnDelete": {
      "description": "Referential action on target delete",
      "type": "string",
      "enum": [
        "restrict",
        "cascade",
        "set_null"
      ]
    },
    "PageBinds": {
      "description": "PageBinds declares the backend footprint of a `mode: custom` page\n(frontend/06-page-kinds.md §13) — the same role as `needs:` on a component\nblock (frontend/07-component-kinds.md §4). Calls outside `binds` fail\nclient-side and are never authorized server-side either.\n",
      "type": "object",
      "properties": {
        "actions": {
          "description": "Actions the page may invoke, as \"module.entity.action\" (or wildcard).",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "entities": {
          "description": "Entities the page may read/write, as \"module.entity\" refs.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "subscribe": {
          "description": "Subscribe channels (entity refs) the page may subscribe to.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "PageBlock": {
      "description": "PageBlock is a compositional unit within a Page.\n",
      "type": "object",
      "properties": {
        "component": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "form": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "html": {
          "type": "string"
        },
        "section": {
          "$ref": "#/$defs/SectionBlock",
          "nullable": true
        },
        "table": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "widget": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "PageLayout": {
      "description": "PageLayout controls block arrangement on a page.\n",
      "type": "object",
      "properties": {
        "columns": {
          "type": "integer"
        },
        "mode": {
          "description": "Layout mode. `split` = master-detail (master list left, detail right).",
          "type": "string",
          "enum": [
            "",
            "split"
          ]
        }
      },
      "additionalProperties": false
    },
    "PageTab": {
      "description": "PageTab is one tab on a tabbed page (Frontend §3, tabs variant).\n",
      "type": "object",
      "properties": {
        "component": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "form": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        },
        "label": {
          "type": "string"
        },
        "table": {
          "$ref": "#/$defs/BlockRef",
          "nullable": true
        }
      },
      "required": [
        "label"
      ],
      "additionalProperties": false
    },
    "ParamInput": {
      "description": "ParamInput is one declared input of an action or transition.\n",
      "type": "object",
      "properties": {
        "compute": {
          "type": "string"
        },
        "default": {
          "description": "Default seeds the input before the user touches it."
        },
        "enum_values": {
          "description": "EnumValues / Options / Multiple describe an ad-hoc input's choice set, the",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "help": {
          "description": "Help is the user-facing hint rendered under the input. On an Entity field",
          "type": "string"
        },
        "label": {
          "description": "Label overrides the caption. Falls back to the Entity field's `title`,",
          "type": "string"
        },
        "multiple": {
          "type": "boolean",
          "nullable": true
        },
        "name": {
          "description": "Parameter name, and the wire key in the request body. Matching an Entity field name makes this a REFERENCE to that field (inheriting type/enum/cardinality, and persisting the collected value); otherwise the input is ad-hoc.",
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "options": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FieldOption"
          }
        },
        "persist": {
          "description": "Persist overrides the destination of a collected value. Absent means the",
          "type": "boolean",
          "nullable": true
        },
        "placeholder": {
          "description": "Placeholder is the empty-state hint inside the input.",
          "type": "string"
        },
        "readonly_when": {
          "type": "string"
        },
        "required": {
          "description": "Required marks the input as unconditionally required. `RequiredWhen`",
          "type": "boolean"
        },
        "required_when": {
          "type": "string"
        },
        "rules": {
          "description": "Rules constrains the collected value. Merged with the Entity field's own",
          "type": "array",
          "items": {
            "$ref": "#/$defs/ValidationRule"
          }
        },
        "type": {
          "$ref": "#/$defs/FieldType",
          "description": "Type is the data type of an AD-HOC input. Required when `name` matches no"
        },
        "visible_when": {
          "description": "Client-behavior vocabulary (`FormSpecExpr`), identical to a Form field's",
          "type": "string"
        },
        "widget": {
          "$ref": "#/$defs/FormWidget",
          "description": "Widget overrides the widget derived from the field's type. A CLOSED set"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "ParamValidation": {
      "description": "ParamValidation validates an action parameter.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "rules": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ValidationRule"
          }
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "ParamsDecl": {
      "description": "ParamsDecl declares what an action or transition accepts: the rules a request\nbody must satisfy (`validate`), and — since the action-input contract — the\ninputs a renderer should COLLECT (`inputs`).\n",
      "type": "object",
      "properties": {
        "inputs": {
          "description": "Inputs declares the parameters richly enough to render: label, widget, and",
          "type": "array",
          "items": {
            "$ref": "#/$defs/ParamInput"
          }
        },
        "inputs_from": {
          "description": "InputsFrom pulls in named `input_sets:` declared on the owning Entity, so",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "render": {
          "$ref": "#/$defs/ParamsRenderHint",
          "description": "Render carries the design-time container decision. Absent means the",
          "nullable": true
        },
        "validate": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ParamValidation"
          }
        }
      },
      "additionalProperties": false
    },
    "ParamsRenderHint": {
      "description": "ParamsRenderHint carries the container decision for an input form, and is\ndeliberately a design-time choice — the same locking `Form.render` has, and\nfor the same reason: whether a dialog or a page appears is a layout decision\na manifest author makes, not something the runtime should second-guess.\n\nWhen absent the renderer derives the container from the input count, matching\n`deriveFormRenderMode` (≤5 modal, 5–12 drawer, \u003e12 separate_page).\n",
      "type": "object",
      "properties": {
        "mode": {
          "description": "Input-form container. Design-time decision, not switchable at runtime.",
          "type": "string",
          "enum": [
            "modal",
            "drawer",
            "separate_page"
          ]
        }
      },
      "additionalProperties": false
    },
    "PayloadDecl": {
      "description": "PayloadDecl declares which entity fields are carried in the event payload (§12).\n",
      "type": "object",
      "properties": {
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "PersistSpec": {
      "description": "PersistSpec controls how an entity is stored (Core §19).\n",
      "type": "object",
      "properties": {
        "category": {
          "description": "operational | financial | compliance | analytics | master | archive",
          "type": "string"
        },
        "indexes": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/IndexDecl"
          }
        },
        "raw_ddl": {
          "description": "RawDDL holds storage-level DDL the spec language does not express —",
          "type": "array",
          "items": {
            "$ref": "#/$defs/RawDDLDecl"
          }
        },
        "soft_delete": {
          "description": "SoftDelete defaults to true; nil means \"not set\" so a persist block",
          "type": "boolean",
          "nullable": true
        },
        "table": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PickerDecl": {
      "description": "PickerDecl declares that a child field is filled by picking records from\nanother entity.\n",
      "type": "object",
      "properties": {
        "display": {
          "$ref": "#/$defs/PickerDisplay",
          "description": "Display describes how a source record is presented as a tile."
        },
        "entity": {
          "description": "Entity is the source entity rows are picked from (`module.entity` or a",
          "type": "string",
          "examples": [
            "cafe-master.menu-item"
          ]
        },
        "filter": {
          "description": "Filter is an equality pre-filter applied to the source list request.",
          "type": "object",
          "additionalProperties": {},
          "examples": [
            "{\\\"is_available\\\": \\\"true\\\"}"
          ]
        },
        "lookup": {
          "$ref": "#/$defs/PickerLookup",
          "description": "Lookup enriches each picked row with a value read from a related entity",
          "nullable": true
        },
        "map": {
          "$ref": "#/$defs/PickerMap",
          "description": "Map describes what gets written into the row."
        }
      },
      "required": [
        "entity",
        "display",
        "map"
      ],
      "additionalProperties": false
    },
    "PickerDisplay": {
      "description": "PickerDisplay is the presentation half of a picker: what the user sees.\n",
      "type": "object",
      "properties": {
        "category_field": {
          "description": "Source relation/enum field rendered as filter chips.",
          "type": "string",
          "examples": [
            "menu_category_id"
          ]
        },
        "columns": {
          "description": "Tile grid columns, 2–4 (default 3).",
          "type": "integer",
          "examples": [
            "3"
          ]
        },
        "description_field": {
          "description": "@schema {example: \"description\"}",
          "type": "string",
          "examples": [
            "description"
          ]
        },
        "empty_text": {
          "description": "@schema {example: \"Belum ada data\"}",
          "type": "string",
          "examples": [
            "Belum ada data"
          ]
        },
        "image_field": {
          "description": "Source field holding an image: a file/attachment field (served from the entity file route) or a string URL.",
          "type": "string",
          "examples": [
            "photo"
          ]
        },
        "name_field": {
          "description": "Source field used as the tile title (default \\\"name\\\").",
          "type": "string",
          "examples": [
            "name"
          ]
        },
        "search": {
          "description": "Client-side search over the tile title.",
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "PickerLookup": {
      "description": "PickerLookup enriches a picked row with a value read from a RELATED entity —\none record per picked row, matched by a key.\n\nGeneric on purpose, and that is the whole point: \"read one value per row from\na table keyed by that row\" is one shape, not a food-ordering feature. Change\nthe nouns and it is a per-outlet price, a per-region tax rate, a per-warehouse\nstock level, a per-clinic fee, a per-tenant quota or a localized label. The\npicker's own entity supplies the ROWS; the lookup supplies the VALUE that goes\nwith each row.\n\nIt is declared on the picker (not on the entity) because the picker is what\ncauses the fetch, so the declaration and the enforcement cannot come from two\ndifferent places.\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "Entity is the related entity the value is read from (`module.entity` or a",
          "type": "string",
          "examples": [
            "cafe-master.menu-item-price"
          ]
        },
        "field": {
          "description": "Field is the field on `entity` whose value is used.",
          "type": "string",
          "examples": [
            "price"
          ]
        },
        "filter": {
          "description": "Filter narrows the lookup list IN THE BROWSER. Values interpolate",
          "type": "object",
          "additionalProperties": {},
          "examples": [
            "{\\\"is_active\\\": \\\"true\\\"}"
          ]
        },
        "key": {
          "description": "Key is the field on `entity` matched against the picked row's source id",
          "type": "string",
          "examples": [
            "menu_item_id"
          ]
        },
        "scope": {
          "description": "Scope is the SERVER-ENFORCED row scope for reads of `entity` caused by this",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilterSpec"
          }
        }
      },
      "required": [
        "entity",
        "key",
        "field"
      ],
      "additionalProperties": false
    },
    "PickerMap": {
      "description": "PickerMap is the write half of a picker: which row field receives what.\n",
      "type": "object",
      "properties": {
        "lookup_field": {
          "description": "LookupField receives `lookup.field` for the picked row (snapshot).",
          "type": "string",
          "examples": [
            "unit_price_snapshot"
          ]
        },
        "max_quantity": {
          "description": "Upper bound per row (default 99).",
          "type": "integer",
          "examples": [
            "20"
          ]
        },
        "name_field": {
          "description": "NameField receives the source record's display name (snapshot).",
          "type": "string",
          "examples": [
            "name_snapshot"
          ]
        },
        "note_field": {
          "description": "NoteField is a free-text per-row note (typed by the user, not copied).",
          "type": "string",
          "examples": [
            "note"
          ]
        },
        "quantity_field": {
          "description": "QuantityField accumulates the picked amount. When omitted, a picked row",
          "type": "string",
          "examples": [
            "quantity"
          ]
        },
        "ref_field": {
          "description": "RefField is the row's relation field pointing back at the source record.",
          "type": "string",
          "examples": [
            "menu_item_id"
          ]
        },
        "source_name_field": {
          "description": "SourceNameField overrides which *source* field the name snapshot reads from",
          "type": "string",
          "examples": [
            "title"
          ]
        }
      },
      "required": [
        "ref_field"
      ],
      "additionalProperties": false
    },
    "PolicyApproval": {
      "description": "PolicyApproval declares an approval rule for a class of implementation types.\n",
      "type": "object",
      "properties": {
        "approver_roles": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "approvers": {
          "type": "integer"
        },
        "impl": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ImplType"
          }
        }
      },
      "required": [
        "approvers"
      ],
      "additionalProperties": false
    },
    "PowDifficulty": {
      "description": "PowDifficulty is the proof-of-work difficulty range (leading zero bits of\nSHA-256). Max is capped at 32 in validation: past that the gate is an\noutage, not a filter.\n",
      "type": "object",
      "properties": {
        "max": {
          "description": "Leading zero bits when saturated (upper bound)",
          "type": "integer",
          "examples": [
            "22"
          ]
        },
        "min": {
          "description": "Leading zero bits when idle (lower bound)",
          "type": "integer",
          "examples": [
            "16"
          ]
        }
      },
      "required": [
        "min",
        "max"
      ],
      "additionalProperties": false
    },
    "PrimitiveType": {
      "description": "ctx.* primitive type this datastore backs",
      "type": "string",
      "enum": [
        "db",
        "cache",
        "lock",
        "queue",
        "pubsub",
        "storage",
        "config",
        "kvstore",
        "log"
      ]
    },
    "PrintBodyItem": {
      "description": "PrintBodyItem is one element in the Print body\n(fields | separator | child_table | totals | qrcode).\n",
      "type": "object",
      "properties": {
        "child_table": {
          "$ref": "#/$defs/PrintChildTable",
          "nullable": true
        },
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "qrcode": {
          "$ref": "#/$defs/PrintQrcode",
          "description": "Qrcode renders a scannable QR code (gap #3 / S4: a table card or a",
          "nullable": true
        },
        "separator": {
          "type": "string"
        },
        "totals": {
          "$ref": "#/$defs/PrintTotals",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "PrintChildTable": {
      "description": "PrintChildTable renders a child-table field in a Print body.\n",
      "type": "object",
      "properties": {
        "columns": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "field": {
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "PrintCustomPaper": {
      "description": "PrintCustomPaper is a custom paper dimension.\n",
      "type": "object",
      "properties": {
        "height": {
          "type": "number"
        },
        "unit": {
          "type": "string"
        },
        "width": {
          "type": "number"
        }
      },
      "required": [
        "width",
        "height",
        "unit"
      ],
      "additionalProperties": false
    },
    "PrintFooter": {
      "description": "PrintFooter is the declarative footer block of a Print document.\n",
      "type": "object",
      "properties": {
        "text": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PrintFormat": {
      "title": "Print Format",
      "description": "Output format for a Print document. Closed set — pdf/thermal are served server-side, html client-side; dotmatrix is not implemented and is rejected.",
      "type": "string",
      "enum": [
        "pdf",
        "thermal",
        "dotmatrix",
        "html"
      ]
    },
    "PrintHeader": {
      "description": "PrintHeader is the declarative header block of a Print document.\n",
      "type": "object",
      "properties": {
        "logo": {
          "type": "boolean"
        },
        "subtitle": {
          "type": "string"
        },
        "title": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PrintMode": {
      "title": "Print Mode",
      "description": "How the document is invoked. `preview` (default) opens the preview dialog; `direct` runs the print/download action as soon as the record loads.",
      "type": "string",
      "enum": [
        "preview",
        "direct"
      ]
    },
    "PrintOutput": {
      "description": "PrintOutput selects the rendering pipeline and paper.\n",
      "type": "object",
      "properties": {
        "format": {
          "$ref": "#/$defs/PrintFormat",
          "description": "pdf | thermal | dotmatrix | html"
        },
        "paper": {
          "$ref": "#/$defs/PrintPaper",
          "nullable": true
        },
        "print_mode": {
          "$ref": "#/$defs/PrintMode",
          "description": "Mode selects how the document is invoked. Empty means `preview` — the"
        }
      },
      "required": [
        "format"
      ],
      "additionalProperties": false
    },
    "PrintPaper": {
      "description": "PrintPaper declares the paper size for a print output.\n",
      "type": "object",
      "properties": {
        "custom": {
          "$ref": "#/$defs/PrintCustomPaper",
          "nullable": true
        },
        "margin": {
          "type": "string"
        },
        "size": {
          "description": "A4 | A5 | thermal_58mm | ...",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "PrintQrcode": {
      "description": "PrintQrcode is a QR code element in a Print body.\n",
      "type": "object",
      "properties": {
        "absolute": {
          "description": "Absolute prepends the origin the document is printed from, so the code",
          "type": "boolean"
        },
        "label": {
          "description": "@schema {example: \"Scan untuk struk digital\"}",
          "type": "string",
          "examples": [
            "Scan untuk struk digital"
          ]
        },
        "payload": {
          "description": "Text the QR encodes. `{dotted.path}` tokens are interpolated from the record, exactly like `header.title`/`footer.text`.",
          "type": "string",
          "examples": [
            "/status/{guest_token}"
          ],
          "minLength": 1
        },
        "size_mm": {
          "description": "QR side length in millimetres (default 30). Thermal maps it to a module size instead of a physical size.",
          "type": "integer",
          "examples": [
            "30"
          ],
          "minimum": 0
        }
      },
      "required": [
        "payload"
      ],
      "additionalProperties": false
    },
    "PrintTotals": {
      "description": "PrintTotals renders a totals line in a Print body.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "format": {
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "ProtocolType": {
      "description": "External protocol type",
      "type": "string",
      "enum": [
        "rest",
        "grpc",
        "ws"
      ]
    },
    "PublicEntityDecl": {
      "description": "PublicEntityDecl grants anonymous access to one entity's actions on a public\nApp's surface (S3). Entity is \"\u003cmodule\u003e/\u003centity\u003e\"; the module MUST be one of\nthe App's spec.modules, so a grant can never reach outside the App bundle.\n",
      "type": "object",
      "properties": {
        "actions": {
          "description": "Closed set: list, find, create, update, delete",
          "type": "array",
          "items": {
            "type": "string"
          },
          "examples": [
            "[list, find]"
          ]
        },
        "entity": {
          "description": "@schema {example: \"cafe-master/menu-item\"}",
          "type": "string",
          "examples": [
            "cafe-master/menu-item"
          ]
        },
        "scope": {
          "description": "Scope is the row filter anonymous reads of this entity must satisfy on",
          "type": "array",
          "items": {
            "$ref": "#/$defs/FilterSpec"
          }
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "PublishDecl": {
      "description": "PublishDecl configures how an event is published.\n",
      "type": "object",
      "properties": {
        "durable": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "RateLimitSpec": {
      "description": "1.4.1 RateLimitSpec — per-resource or per-action rate limit (02-core-extended.md §17).\n",
      "type": "object",
      "properties": {
        "max": {
          "type": "integer"
        },
        "per": {
          "description": "e.g. \"1s\", \"1m\", \"1h\"",
          "type": "string"
        },
        "scope": {
          "description": "tenant | user | ip | global",
          "type": "string"
        },
        "strategy": {
          "description": "sliding_window | token_bucket",
          "type": "string"
        }
      },
      "required": [
        "max",
        "per"
      ],
      "additionalProperties": false
    },
    "RawDDLDecl": {
      "description": "RawDDLDecl is one storage-level DDL statement declared on an Entity\n(01-core-basic.md §4.3).\n",
      "type": "object",
      "properties": {
        "ddl": {
          "description": "DDL is one statement valid on every driver.",
          "type": "string",
          "examples": [
            "CREATE INDEX idx_invoice_date ON invoice(transaction_date)"
          ]
        },
        "ddl_by": {
          "description": "DDLByDialect holds per-driver variants, for DDL that cannot be written",
          "type": "object",
          "additionalProperties": {}
        },
        "name": {
          "description": "Name identifies the statement for recording and reporting.",
          "type": "string",
          "examples": [
            "menu-price-unique"
          ],
          "minLength": 1,
          "pattern": "^[a-z][a-z0-9_-]*$"
        },
        "reason": {
          "description": "Reason states why the DDL is needed (audit trail).",
          "type": "string",
          "examples": [
            "satu harga per menu per cabang"
          ]
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "RebuildSpec": {
      "description": "RebuildSpec describes how a summary entity is rebuilt from its durable\nsource event/record stream.\n",
      "type": "object",
      "properties": {
        "since": {
          "type": "string"
        },
        "strategy": {
          "description": "full | partial | none",
          "type": "string"
        },
        "window": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "RegisteredViewDecl": {
      "description": "RegisteredViewDecl is one extra view an App exposes beyond its menu\n(App.spec.registered_views — plan docs_internal/plan/registered-views.md).\nExactly one of Entity/View is set:\n\n  - Entity grants every derived view of one entity (list/detail/create/edit);\n  - View grants one registered navigable view by name.\n\nEntity accepts \"module/entity\" or \"module.entity\" (normalized via\nNormalizeEntityRef); View accepts \"module/name\". The module MUST be one of the\nApp's spec.modules, so a declaration can never reach outside the App bundle.\nExistence of the referenced entity/view is checked at resolve time (it needs\nthe UI/entity registries).\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "@schema {example: \"cafe-master/menu-item\"}",
          "type": "string",
          "examples": [
            "cafe-master/menu-item"
          ]
        },
        "view": {
          "description": "@schema {example: \"cafe-order/menu-catalog\"}",
          "type": "string",
          "examples": [
            "cafe-order/menu-catalog"
          ]
        }
      },
      "additionalProperties": false
    },
    "RegistrationSettings": {
      "description": "RegistrationSettings configures the workspace-level self-service sign-up\npolicy (auth redesign Fase 4). Per-workspace — applies to every App in the\nworkspace.\n\n  - open     (default): sign-up creates an active user with DefaultRole.\n  - approval: sign-up creates a pending user; an admin approves + assigns\n    the role before the user can log in.\n  - closed:   self-service sign-up is disabled; admins create users.\n",
      "type": "object",
      "properties": {
        "default_role": {
          "description": "DefaultRole is assigned on sign-up when Policy is \"open\" (e.g. \"user\").",
          "type": "string"
        },
        "policy": {
          "description": "@schema {enum: [\"open\", \"approval\", \"closed\"], default: \"open\"}",
          "type": "string",
          "enum": [
            "open",
            "approval",
            "closed"
          ]
        }
      },
      "additionalProperties": false
    },
    "RelationDecl": {
      "description": "RelationDecl defines a relation to another entity.\n@schema {title: \"Relation Declaration\"}\n",
      "type": "object",
      "properties": {
        "foreign_key": {
          "type": "string"
        },
        "on_delete": {
          "$ref": "#/$defs/OnDelete",
          "description": "restrict | cascade | set_null (v0.3.0)"
        },
        "resource": {
          "description": "Target entity \\\"module/entity\\\" or just \\\"entity\\\" within same module",
          "type": "string"
        },
        "snapshot": {
          "description": "Snapshot copies master financial fields to the transaction at",
          "type": "array",
          "items": {
            "$ref": "#/$defs/SnapshotField"
          }
        },
        "type": {
          "description": "Relation type: belongs_to (FK on this entity), has_many (FK on target), has_one (FK on target, unique)",
          "type": "string",
          "enum": [
            "belongs_to",
            "has_many",
            "has_one"
          ]
        }
      },
      "required": [
        "type",
        "resource"
      ],
      "additionalProperties": false
    },
    "ReportAggregate": {
      "title": "Report Aggregate",
      "description": "Aggregation applied to a report column. Closed set — mirrors the Query Builder's aggregate functions.",
      "type": "string",
      "enum": [
        "sum",
        "avg",
        "count",
        "min",
        "max"
      ]
    },
    "ReportColumn": {
      "description": "ReportColumn is a column in a report output.\n",
      "type": "object",
      "properties": {
        "aggregate": {
          "$ref": "#/$defs/ReportAggregate",
          "description": "Aggregate is a closed set (S16) — mirrors the Query Builder's aggregate"
        },
        "field": {
          "type": "string"
        },
        "format": {
          "$ref": "#/$defs/ReportFormat",
          "description": "Format is a closed set (S16) — every name is implemented by the report"
        },
        "label": {
          "type": "string"
        },
        "widget": {
          "$ref": "#/$defs/TableCellWidget",
          "description": "Widget renders the cell like a table cell (S16) — the same closed set as"
        }
      },
      "required": [
        "field",
        "label"
      ],
      "additionalProperties": false
    },
    "ReportFormat": {
      "title": "Report Format",
      "description": "Value formatter for a report column. Closed set — every name is implemented by the report renderer.",
      "type": "string",
      "enum": [
        "currency",
        "date",
        "datetime",
        "percentage"
      ]
    },
    "ReportGroup": {
      "description": "ReportGroup defines a grouping level in a report.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "label": {
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "ReportParam": {
      "description": "ReportParam is a filterable input for a report.\n",
      "type": "object",
      "properties": {
        "default": {},
        "field": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "required": {
          "type": "boolean"
        },
        "type": {
          "$ref": "#/$defs/ReportParamType"
        }
      },
      "required": [
        "field",
        "label",
        "type"
      ],
      "additionalProperties": false
    },
    "ReportParamType": {
      "title": "Report Param Type",
      "description": "Input type for a report parameter. Closed set — every name is implemented by the report renderer.",
      "type": "string",
      "enum": [
        "text",
        "date",
        "datetime",
        "select",
        "relation"
      ]
    },
    "ReportSource": {
      "description": "ReportSource declares the report's data source + parameterized filter.\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "@schema {example: \"billing.order\"}",
          "type": "string",
          "examples": [
            "billing.order"
          ]
        },
        "filter": {
          "description": "Filter maps a list-API filter field to a literal value or a `\":param\"`",
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "ReportTotal": {
      "description": "ReportTotal defines a total/aggregate row.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "fn": {
          "description": "sum | avg | count | min | max",
          "type": "string"
        },
        "label": {
          "type": "string"
        }
      },
      "required": [
        "label",
        "field",
        "fn"
      ],
      "additionalProperties": false
    },
    "RetryDecl": {
      "description": "RetryDecl configures retry behavior for reliable event delivery.\n",
      "type": "object",
      "properties": {
        "backoff": {
          "description": "exponential | linear | fixed",
          "type": "string"
        },
        "initial_delay_ms": {
          "type": "integer"
        },
        "max": {
          "type": "integer"
        }
      },
      "additionalProperties": false
    },
    "RoundingMode": {
      "description": "RoundingMode is the rounding strategy for money/decimal arithmetic.\n",
      "type": "string",
      "enum": [
        "half_even",
        "half_up",
        "half_down",
        "up",
        "down"
      ]
    },
    "ScopeDecl": {
      "description": "ScopeDecl declares that an entity's rows are partitioned along a named\ndimension (S5). `Field` is the field on this entity that carries the dimension\nvalue; `Required` asserts that every row carries one.\n",
      "type": "object",
      "properties": {
        "dimension": {
          "description": "Dimension name, e.g. branch / tenant / region",
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$"
        },
        "enforced": {
          "description": "Who keeps reads inside the dimension: session (default), route, none (cross-cutting by design), external (public grant / create_scope).",
          "type": "string",
          "enum": [
            "session",
            "route",
            "none",
            "external"
          ]
        },
        "field": {
          "description": "Field on this entity carrying the dimension value",
          "type": "string"
        },
        "required": {
          "description": "Every row must carry a dimension value; requires the field itself to be required",
          "type": "boolean"
        }
      },
      "required": [
        "dimension",
        "field"
      ],
      "additionalProperties": false
    },
    "SectionBlock": {
      "description": "SectionBlock is a declarative presentation section inside a Page\n(frontend/06-page-kinds.md §1). Sections are generic — reusable in any App\n(marketing/hero, no-nav, sidebar-nav, ...): pure presentation, no data\nbinding, no auth, and zero styling fields — every visual token lives in\nkind: Theme (frontend/05-app-kinds.md §5), never inline.\n",
      "type": "object",
      "properties": {
        "align": {
          "description": "Align controls text alignment of title/subtitle/items — left (default)",
          "type": "string",
          "enum": [
            "left",
            "center",
            "right"
          ]
        },
        "autoplay": {
          "description": "Autoplay + IntervalMS drive carousel auto-advance (default off / 5000ms).",
          "type": "boolean"
        },
        "columns": {
          "description": "Columns controls the grid width for feature_grid / card (default 3).",
          "type": "integer"
        },
        "cta": {
          "$ref": "#/$defs/SectionCTA",
          "nullable": true
        },
        "image": {
          "description": "@schema {example: \"assets/hero.png\"}",
          "type": "string",
          "examples": [
            "assets/hero.png"
          ]
        },
        "interval_ms": {
          "type": "integer"
        },
        "items": {
          "description": "Items is the content list for feature_grid / card / carousel.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/SectionItem"
          }
        },
        "subtitle": {
          "description": "@schema {example: \"Satu platform untuk jadwal, pasien, dan tagihan.\"}",
          "type": "string",
          "examples": [
            "Satu platform untuk jadwal, pasien, dan tagihan."
          ]
        },
        "title": {
          "description": "@schema {example: \"Kelola klinik Anda\"}",
          "type": "string",
          "examples": [
            "Kelola klinik Anda"
          ]
        },
        "type": {
          "description": "Section block type — closed set.",
          "type": "string",
          "enum": [
            "hero",
            "feature_grid",
            "card",
            "carousel",
            "cta"
          ]
        },
        "variant": {
          "description": "@schema {example: \"primary\"}",
          "type": "string",
          "examples": [
            "primary"
          ]
        }
      },
      "required": [
        "type"
      ],
      "additionalProperties": false
    },
    "SectionCTA": {
      "description": "SectionCTA is one call-to-action link inside a section block.\n",
      "type": "object",
      "properties": {
        "href": {
          "description": "@schema {example: \"/app\"}",
          "type": "string",
          "examples": [
            "/app"
          ]
        },
        "label": {
          "description": "@schema {example: \"Mulai\"}",
          "type": "string",
          "examples": [
            "Mulai"
          ]
        },
        "variant": {
          "description": "@schema {example: \"primary\", enum: [\"primary\", \"secondary\", \"ghost\"]}",
          "type": "string",
          "enum": [
            "primary",
            "secondary",
            "ghost"
          ],
          "examples": [
            "primary"
          ]
        }
      },
      "required": [
        "label",
        "href"
      ],
      "additionalProperties": false
    },
    "SectionItem": {
      "description": "SectionItem is one content entry in a feature_grid / card / carousel block.\n",
      "type": "object",
      "properties": {
        "cta": {
          "$ref": "#/$defs/SectionCTA",
          "nullable": true
        },
        "icon": {
          "description": "Icon is a lucide icon name (renderer-specific; closed to the shell's",
          "type": "string"
        },
        "image": {
          "type": "string"
        },
        "text": {
          "type": "string"
        },
        "title": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "SeedEntity": {
      "description": "SeedEntity declares the records to insert for a single entity.\n",
      "type": "object",
      "properties": {
        "entity": {
          "description": "Entity name inside metadata.module",
          "type": "string",
          "examples": [
            "menu-item"
          ]
        },
        "records": {
          "description": "Raw entity payloads (same shape as an API create body); supports `$ref` for relations and `$asset` for file fields",
          "type": "array",
          "items": {
            "type": "object",
            "additionalProperties": {}
          }
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "Settings": {
      "description": "Settings is the typed global presentation/config namespace. It is declared\nonce on a workspace/App `kind: Config` manifest under `settings:` and\nresolved with standard defaults so behavior is consistent across every\ncomponent even when unset. Renderers/backends read these values instead of\nguessing per component (01-core-basic.md §10, 05-field-types.md §2).\n",
      "type": "object",
      "properties": {
        "auth": {
          "$ref": "#/$defs/AuthSettings",
          "description": "Auth configures external authentication providers (auth redesign Fase 5",
          "nullable": true
        },
        "currency": {
          "$ref": "#/$defs/CurrencySettings",
          "description": "Currency is the default money currency for the workspace (ISO-4217 code,",
          "nullable": true
        },
        "date_format": {
          "description": "DateFormat is the display date format (e.g. \"YYYY-MM-DD\", \"DD/MM/YYYY\").",
          "type": "string"
        },
        "decimal_scale": {
          "description": "DecimalScale is the default number of digits after the decimal point for",
          "type": "integer"
        },
        "locale": {
          "description": "Locale is the IETF BCP-47 locale used for number/date formatting",
          "type": "string"
        },
        "registration": {
          "$ref": "#/$defs/RegistrationSettings",
          "description": "Registration is the workspace-level self-service sign-up policy",
          "nullable": true
        },
        "rounding": {
          "description": "Rounding is the default rounding mode for money/decimal arithmetic:",
          "type": "string"
        },
        "timezone": {
          "description": "Timezone is the IANA timezone name (e.g. \"UTC\", \"Asia/Jakarta\").",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "SlotContract": {
      "description": "SlotContract defines the props contract for a slot.\n",
      "type": "object",
      "properties": {
        "optional_props": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "required_props": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "SlotDecl": {
      "description": "SlotDecl declares a named slot with its data contract (02-visual-spec-kind.md §4).\n",
      "type": "object",
      "properties": {
        "contract": {
          "$ref": "#/$defs/SlotContract",
          "nullable": true
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "SnapshotField": {
      "description": "SnapshotField copies one master field into the transaction at create/submit\n(02-core-extended.md §1.1, todo 7.10).\n",
      "type": "object",
      "properties": {
        "as": {
          "description": "As is the target field name on the transaction (default = From).",
          "type": "string"
        },
        "from": {
          "description": "From is the master field name to copy.",
          "type": "string"
        }
      },
      "required": [
        "from"
      ],
      "additionalProperties": false
    },
    "SoftDeactivateDecl": {
      "description": "1.4.10 SoftDeactivateDecl — soft-deactivation pattern for master entities\n(02-core-extended.md §19). Adds is_active field + deactivate/reactivate actions.\n",
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "StateDecl": {
      "description": "StateDecl defines a named state.\n",
      "type": "object",
      "properties": {
        "description": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "label"
      ],
      "additionalProperties": false
    },
    "StateMachine": {
      "description": "StateMachine defines entity lifecycle states and transitions.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "initial": {
          "type": "string"
        },
        "states": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/StateDecl"
          }
        },
        "transitions": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TransitionDecl"
          }
        }
      },
      "required": [
        "field",
        "initial"
      ],
      "additionalProperties": false
    },
    "StepEscalation": {
      "description": "StepEscalation configures the timeout and the takeover that follows it for one\nstep.\n\nBoth fields are required together. The only escalation effect the engine\nimplements is REASSIGNMENT, so an `after` with nothing to reassign to — or a\nreassign with no timeout to fire — would pass through silently and change\nnothing at all. That is the same \"declaration with no effect\" shape this file\nkeeps refusing, and it is why `notify_roles` was removed: notification delivery\ndoes not exist, so the field could never have done anything.\n",
      "type": "object",
      "properties": {
        "after": {
          "description": "@schema {example: \"48h\"}",
          "type": "string",
          "examples": [
            "48h"
          ]
        },
        "reassign": {
          "description": "Reassign names the DUTY that gains approval rights when the timeout fires.",
          "type": "string",
          "examples": [
            "manager-check"
          ]
        }
      },
      "required": [
        "after",
        "reassign"
      ],
      "additionalProperties": false
    },
    "StorageSpec": {
      "description": "1.4.11 StorageSpec — file field configuration (05-field-types.md §1.3).\nOnly valid on Field.Type == FieldFile.\n",
      "type": "object",
      "properties": {
        "allowed_types": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "cdn": {
          "type": "boolean"
        },
        "chunk_size_mb": {
          "description": "ChunkSizeMB is the client hint for chunked-upload part size (todo",
          "type": "integer"
        },
        "download_cache_ttl": {
          "description": "DownloadCacheTTL is how long a browser may reuse a downloaded file without",
          "type": "string"
        },
        "max_count": {
          "type": "integer"
        },
        "max_download_mb": {
          "description": "MaxDownloadMB caps the size of a file served via download/link routes",
          "type": "integer"
        },
        "max_size_mb": {
          "type": "integer"
        },
        "one_time": {
          "description": "OneTime deletes the object after the configured number of successful",
          "type": "boolean"
        },
        "signed_url_ttl": {
          "description": "e.g. \"15m\"",
          "type": "string"
        },
        "transform": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/StorageTransform"
          }
        },
        "ttl": {
          "description": "TTL auto-deletes the object if it is not downloaded within the",
          "type": "string"
        },
        "visibility": {
          "description": "public | private | signed",
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "StorageTransform": {
      "description": "StorageTransform declares an image transformation preset for a file field.\n",
      "type": "object",
      "properties": {
        "fit": {
          "description": "cover | contain | fill",
          "type": "string"
        },
        "height": {
          "type": "integer"
        },
        "name": {
          "type": "string"
        },
        "width": {
          "type": "integer"
        }
      },
      "required": [
        "name"
      ],
      "additionalProperties": false
    },
    "SubDeliveryDecl": {
      "description": "SubDeliveryDecl configures the delivery channel for a subscription (02-core-extended.md §3).\n",
      "type": "object",
      "properties": {
        "channel": {
          "description": "webhook | notification | pubsub | queue",
          "type": "string"
        },
        "header": {
          "description": "header name for url_from: header",
          "type": "string"
        },
        "sign": {
          "type": "boolean"
        },
        "url_from": {
          "description": "header | config",
          "type": "string"
        }
      },
      "required": [
        "channel"
      ],
      "additionalProperties": false
    },
    "SummarySource": {
      "description": "SummarySource describes one durable source entity used to rebuild a summary\nprojection. The concrete join semantics are implementation-defined but the\ncontract is the same across backends: combine these sources by join_key.\nSee docs/spec/backend/02-core-extended.md §6.\n",
      "type": "object",
      "properties": {
        "alias": {
          "type": "string"
        },
        "entity": {
          "type": "string"
        },
        "filter": {
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "entity"
      ],
      "additionalProperties": false
    },
    "TableAction": {
      "description": "TableAction is a clickable action on a table row or bulk selection.\n",
      "type": "object",
      "properties": {
        "action": {
          "type": "string"
        },
        "confirm_msg": {
          "type": "string"
        },
        "icon": {
          "type": "string"
        },
        "label": {
          "type": "string"
        },
        "view": {
          "description": "Navigate to a view resource (`\u003ckind\u003e:\u003cname\u003e`, e.g. `print:receipt-thermal`) instead of running the entity action. The record id is appended for kinds whose route takes one.",
          "type": "string",
          "examples": [
            "print:table-tent-card"
          ]
        }
      },
      "required": [
        "action",
        "label"
      ],
      "additionalProperties": false
    },
    "TableCellFormat": {
      "title": "Table Cell Format",
      "description": "Value formatter for a table/listing cell. Closed set — every name is implemented by the cell renderer.",
      "type": "string",
      "enum": [
        "currency",
        "number",
        "date",
        "relative",
        "percent"
      ]
    },
    "TableCellWidget": {
      "title": "Table Cell Widget",
      "description": "Widget rendering a table or listing cell. Closed set — every name is implemented by the cell renderer; omit to render the raw value (optionally via `format`).",
      "type": "string",
      "enum": [
        "badge",
        "boolean",
        "image",
        "qrcode"
      ]
    },
    "TableColumn": {
      "description": "TableColumn configures a table column.\n",
      "type": "object",
      "properties": {
        "align": {
          "description": "Text alignment of this column's header and body cells.",
          "type": "string",
          "enum": [
            "",
            "left",
            "center",
            "right"
          ]
        },
        "field": {
          "type": "string"
        },
        "format": {
          "$ref": "#/$defs/TableCellFormat",
          "description": "Format is the value formatter for this cell. Closed set — every name is"
        },
        "label": {
          "type": "string"
        },
        "link": {
          "description": "Page name to navigate to when this cell is clicked.",
          "type": "string"
        },
        "sortable": {
          "type": "boolean"
        },
        "widget": {
          "$ref": "#/$defs/TableCellWidget"
        },
        "width": {
          "description": "CSS width for this column, applied to the header cell (e.g. \\\"120px\\\", \\\"10rem\\\").",
          "type": "string"
        }
      },
      "required": [
        "field"
      ],
      "additionalProperties": false
    },
    "TimelineDisplay": {
      "description": "TimelineDisplay maps entity fields to timeline card slots.\n",
      "type": "object",
      "properties": {
        "component": {
          "type": "string"
        },
        "content_field": {
          "type": "string"
        },
        "icon_field": {
          "type": "string"
        },
        "subtitle_field": {
          "type": "string"
        },
        "title_field": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "TransitionDecl": {
      "description": "TransitionDecl defines a transition between states (Core §14).\nThe canonical manifest key for the triggering action is `via`;\n`action` is accepted as a legacy alias.\n",
      "type": "object",
      "properties": {
        "approval": {
          "$ref": "#/$defs/ApprovalSpec",
          "description": "Approval gates this transition behind an approval chain (02-core-extended.md",
          "nullable": true
        },
        "audit": {
          "description": "Audit records this transition in the business audit trail. Meaningful only",
          "type": "boolean"
        },
        "conditions": {
          "description": "Conditions gate the transition ACTION before it runs (e.g. a required",
          "type": "array",
          "items": {
            "$ref": "#/$defs/ConditionDecl"
          }
        },
        "description": {
          "description": "Deskripsi transisi; dipakai sebagai label tombol bila `ui.button_label` tidak ada.",
          "type": "string",
          "examples": [
            "Semua pesanan meja sudah disajikan"
          ]
        },
        "emit": {
          "description": "Emit names the event this transition publishes when it fires (S13). It",
          "type": "string"
        },
        "emits": {
          "description": "Emits publishes an event when this transition fires. Distinct from",
          "type": "string"
        },
        "expose": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "from": {
          "oneOf": [
            {
              "description": "Single source state name",
              "type": "string"
            },
            {
              "description": "List of source state names",
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ]
        },
        "guard": {
          "$ref": "#/$defs/GuardDecl",
          "nullable": true
        },
        "idempotency_key": {
          "$ref": "#/$defs/IdempotencyDecl",
          "nullable": true
        },
        "idempotent": {
          "description": "Idempotent / IdempotencyKey apply to a transition that has an `impl` and",
          "type": "boolean"
        },
        "impl": {
          "$ref": "#/$defs/ImplDecl",
          "description": "Impl makes this transition an ACTION WITH A ROUTE, exactly like a declared",
          "nullable": true
        },
        "params": {
          "$ref": "#/$defs/ParamsDecl",
          "nullable": true
        },
        "rate_limit": {
          "$ref": "#/$defs/RateLimitSpec",
          "nullable": true
        },
        "require_permission": {
          "description": "Permission the caller must hold to run this transition (own-module prefix may be omitted — same convention as Action.required_permission).",
          "type": "string",
          "examples": [
            "dining-tables.release"
          ]
        },
        "to": {
          "type": "string"
        },
        "ui": {
          "$ref": "#/$defs/ActionUIHint",
          "description": "UI carries the button hints for this transition (label, style, icon,",
          "nullable": true
        },
        "uses": {
          "$ref": "#/$defs/UsesDecl",
          "description": "Uses / Params / Expose / RateLimit complete the \"via is a full action\"",
          "nullable": true
        },
        "via": {
          "type": "string"
        }
      },
      "required": [
        "to",
        "via"
      ],
      "additionalProperties": false
    },
    "UnitDecl": {
      "description": "UnitDecl declares the unit dimension of a field (S12): `Base` is the unit\nvalues are stored in, `Convertible` lists the units callers may convert\nto/from. Both are validated against the field's enum values, so a typo cannot\nsilently disable conversion.\n",
      "type": "object",
      "properties": {
        "base": {
          "description": "Base (storage) unit, e.g. gram",
          "type": "string",
          "minLength": 1
        },
        "convertible": {
          "description": "Units convertible to/from the base unit",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "factors": {
          "description": "Factors maps each convertible unit to how many base units one of it is",
          "type": "object",
          "additionalProperties": {}
        }
      },
      "required": [
        "base"
      ],
      "additionalProperties": false
    },
    "UsesConfigDecl": {
      "description": "UsesConfigDecl specifies config access.\n",
      "type": "object",
      "properties": {
        "read": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "write": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "UsesDbDecl": {
      "description": "UsesDbDecl specifies raw database access per category/module (§11.2).\nDefaults to own module; cross-module write is high-risk consent (D46).\n",
      "type": "object",
      "properties": {
        "read": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "write": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "UsesDecl": {
      "description": "UsesDecl declares what resources/primitives/config an action needs (§11.2).\n",
      "type": "object",
      "properties": {
        "config": {
          "$ref": "#/$defs/UsesConfigDecl",
          "nullable": true
        },
        "datastores": {
          "description": "primitive → datastore name binding",
          "type": "object",
          "additionalProperties": {}
        },
        "db": {
          "$ref": "#/$defs/UsesDbDecl",
          "nullable": true
        },
        "kvstore": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/KvstoreUseDecl"
          }
        },
        "primitives": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "resources": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "secrets": {
          "description": "1.4.2 ctx.secrets access keys (02-core-extended.md §18)",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    },
    "ValidationRule": {
      "description": "Validation constraint. Supports 4 YAML formats: string (\\\"required\\\"), colon (\\\"after:end_date\\\"), map-shorthand ({min_length: 1}), or full ({name: \\\"min_length\\\", value: 1})",
      "oneOf": [
        {
          "description": "Shorthand rule name — e.g. \"required\", \"positive\", \"past\"",
          "type": "string"
        },
        {
          "type": "object",
          "properties": {
            "name": {
              "description": "Validation rule name",
              "type": "string"
            },
            "value": {
              "description": "Validation rule value (optional)"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        {
          "type": "object",
          "additionalProperties": {
            "description": "Rule value — string, number, or boolean"
          },
          "minProperties": 1,
          "maxProperties": 1
        }
      ]
    },
    "WebhookAuth": {
      "description": "WebhookAuth declares how inbound webhook payloads are verified.\nstrategy: signature | token\n",
      "type": "object",
      "properties": {
        "signature": {
          "$ref": "#/$defs/WebhookSigConfig",
          "nullable": true
        },
        "strategy": {
          "description": "signature | token",
          "type": "string"
        },
        "token": {
          "$ref": "#/$defs/WebhookTokenConfig",
          "description": "Token configures static-token verification (strategy: token). The token",
          "nullable": true
        }
      },
      "required": [
        "strategy"
      ],
      "additionalProperties": false
    },
    "WebhookDeliveryDecl": {
      "description": "WebhookDeliveryDecl declares where a `webhook` delivery entry posts the event.\n\nUNSIGNED, deliberately, for this first version: there is no HMAC signature and\nno subscriber registry. The endpoint is declared where the consequence is —\n`url:` literally, or `url_from: {config: \u003ckey\u003e}` when the address belongs to\ndeployment config rather than to the module. Signing needs a per-subscriber\nsecret store, which is a separate decision (todo 7.7.6); until then a signed\nentry would be a promise the runtime cannot keep.\n",
      "type": "object",
      "properties": {
        "headers": {
          "description": "Headers are extra request headers (e.g. a routing key). Values may contain",
          "type": "object",
          "additionalProperties": {}
        },
        "url": {
          "description": "URL is the endpoint, literal. Use `url_from` when the address is",
          "type": "string",
          "examples": [
            "https://example.com/hooks/order-paid"
          ]
        },
        "url_from": {
          "$ref": "#/$defs/WebhookURLRef",
          "description": "URLFrom resolves the endpoint from a Config key instead of a literal.",
          "nullable": true
        }
      },
      "additionalProperties": false
    },
    "WebhookKeyRef": {
      "description": "WebhookKeyRef references the secret key via config.\n",
      "type": "object",
      "properties": {
        "config": {
          "type": "string"
        },
        "secret": {
          "type": "boolean"
        }
      },
      "required": [
        "config"
      ],
      "additionalProperties": false
    },
    "WebhookSigConfig": {
      "description": "WebhookSigConfig configures HMAC signature verification.\n",
      "type": "object",
      "properties": {
        "algorithm": {
          "description": "e.g. hmac-sha512",
          "type": "string"
        },
        "header": {
          "description": "signature header name",
          "type": "string"
        },
        "key": {
          "$ref": "#/$defs/WebhookKeyRef",
          "description": "config reference for the secret key",
          "nullable": true
        },
        "payload": {
          "description": "raw_body | parsed",
          "type": "string"
        }
      },
      "required": [
        "algorithm",
        "header",
        "key"
      ],
      "additionalProperties": false
    },
    "WebhookTokenConfig": {
      "description": "WebhookTokenConfig configures static-token verification for simple internal\nwebhooks (02-core-extended.md §4). The token is referenced via config so it\nnever appears inline in the manifest.\n",
      "type": "object",
      "properties": {
        "header": {
          "description": "Header is the request header carrying the token (e.g. \"Authorization\").",
          "type": "string"
        },
        "key": {
          "$ref": "#/$defs/WebhookKeyRef",
          "description": "Key references the config key holding the expected token value.",
          "nullable": true
        }
      },
      "required": [
        "header",
        "key"
      ],
      "additionalProperties": false
    },
    "WebhookURLRef": {
      "description": "WebhookURLRef resolves a webhook endpoint from a Config key.\n",
      "type": "object",
      "properties": {
        "config": {
          "description": "@schema {example: \"billing.webhook_url\"}",
          "type": "string",
          "examples": [
            "billing.webhook_url"
          ]
        }
      },
      "required": [
        "config"
      ],
      "additionalProperties": false
    },
    "WidgetLayout": {
      "description": "WidgetLayout controls grid placement.\n",
      "type": "object",
      "properties": {
        "h": {
          "type": "integer"
        },
        "w": {
          "type": "integer"
        },
        "x": {
          "type": "integer"
        },
        "y": {
          "type": "integer"
        }
      },
      "required": [
        "x",
        "y",
        "w",
        "h"
      ],
      "additionalProperties": false
    },
    "WizardOnComplete": {
      "description": "WizardOnComplete controls what happens after a successful final submit.\n",
      "type": "object",
      "properties": {
        "banner": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/WizardSummaryItem"
          }
        },
        "redirect": {
          "type": "string"
        },
        "restart": {
          "type": "boolean"
        }
      },
      "additionalProperties": false
    },
    "WizardStep": {
      "description": "WizardStep is one step in a multi-step wizard.\n",
      "type": "object",
      "properties": {
        "allow_create": {
          "type": "boolean"
        },
        "component": {
          "type": "string"
        },
        "depends_on": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "entity": {
          "type": "string"
        },
        "fields": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/FormField"
          }
        },
        "form": {
          "type": "string"
        },
        "layout": {
          "description": "search_select | ...",
          "type": "string"
        },
        "on_enter": {
          "description": "fires when the step becomes active",
          "type": "string"
        },
        "on_next": {
          "description": "fires on Next, before advancing",
          "type": "string"
        },
        "on_prev": {
          "description": "fires on Previous, before going back",
          "type": "string"
        },
        "required": {
          "description": "fields that gate the Next button",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "search_fields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "summary": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/WizardSummaryItem"
          }
        },
        "title": {
          "type": "string"
        }
      },
      "required": [
        "title"
      ],
      "additionalProperties": false
    },
    "WizardSummaryItem": {
      "description": "WizardSummaryItem is one line on a wizard confirmation step.\n",
      "type": "object",
      "properties": {
        "field": {
          "type": "string"
        },
        "label": {
          "type": "string"
        }
      },
      "required": [
        "label",
        "field"
      ],
      "additionalProperties": false
    }
  },
  "title": "FormSpec Manifest",
  "description": "JSON Schema for FormSpec YAML manifests (formspec.dev/v1).\nValidates the apiVersion/kind/metadata/spec structure and routes to kind-specific specs.",
  "type": "object",
  "properties": {
    "apiVersion": {
      "description": "FormSpec API version — must be formspec.dev/v1",
      "type": "string",
      "const": "formspec.dev/v1"
    },
    "kind": {
      "description": "Resource kind — determines the structure of `spec`",
      "type": "string",
      "enum": [
        "Api",
        "App",
        "ApprovalInbox",
        "Calendar",
        "Config",
        "Dashboard",
        "Datastore",
        "Entity",
        "Environment",
        "Form",
        "Integrator",
        "Kanban",
        "KindDefinition",
        "Listing",
        "Mockup",
        "Module",
        "NotificationCenter",
        "Page",
        "PersistBackend",
        "Policy",
        "Print",
        "Renderer",
        "Report",
        "Seed",
        "Service",
        "Subscription",
        "Table",
        "Theme",
        "Timeline",
        "VisualSpecKind",
        "Webhook",
        "Widget",
        "Wizard",
        "Workspace"
      ]
    },
    "metadata": {
      "$ref": "#/$defs/Metadata"
    },
    "spec": {
      "description": "Kind-specific specification — structure depends on `kind`"
    }
  },
  "required": [
    "apiVersion",
    "kind",
    "metadata",
    "spec"
  ],
  "oneOf": [
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "App"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "App Spec",
          "description": "AppSpec is the root project manifest (Core §4.4). A Workspace MAY contain\nmore than one App; all Apps in a workspace run simultaneously, mounted at\ntheir own RootURL.\n",
          "type": "object",
          "properties": {
            "access": {
              "$ref": "#/$defs/AppAccess",
              "description": "@schema {example: \"private\", enum: [\"private\", \"public\"], description: \"Auth axis: private (default, secure by default) | public — orthogonal to app_renderer\"}"
            },
            "app_renderer": {
              "description": "Chrome archetype (frontend/05-app-kinds.md): sidebar-nav | topnav | no-nav — no-nav means truly no navigation",
              "type": "string",
              "enum": [
                "sidebar-nav",
                "topnav",
                "no-nav"
              ],
              "examples": [
                "no-nav"
              ]
            },
            "auth": {
              "$ref": "#/$defs/AppAuth",
              "description": "Auth overrides the auth screens (login, setup, change-password,",
              "nullable": true
            },
            "auth_config_ref": {
              "description": "Per-App auth strategy config (kind: Config)",
              "type": "string"
            },
            "chrome": {
              "$ref": "#/$defs/AppChrome",
              "description": "Chrome fine-tunes which shell chrome elements render (frontend/",
              "nullable": true
            },
            "confirm": {
              "$ref": "#/$defs/AppConfirm",
              "description": "Confirm sets App-wide default confirmation dialogs for mutating",
              "nullable": true
            },
            "consumes": {
              "description": "cross-app interfaces needed → grant request",
              "type": "array",
              "items": {
                "$ref": "#/$defs/AppConsume"
              }
            },
            "datastores": {
              "description": "Datastores is the App-level App Registry selection — the App Registry",
              "type": "object",
              "additionalProperties": {},
              "examples": [
                "db: pg-main"
              ]
            },
            "favicon": {
              "description": "Browser tab icon: spec-root-relative module asset ref to an image file (contains \\\"/\\\"). Optional — falls back to an image `logo`, else the built-in favicon",
              "type": "string",
              "examples": [
                "workspaces/kedai-teras.svg"
              ]
            },
            "intake": {
              "$ref": "#/$defs/IntakeSpec",
              "description": "Intake declares protection for this App's ANONYMOUS intake surface",
              "nullable": true
            },
            "logo": {
              "description": "Brand mark: a lucide icon name (e.g. \\\"package\\\") OR a spec-root-relative module asset ref to an image file (contains \\\"/\\\", e.g. \\\"modules/\u003cmodule\u003e/assets/\u003cfile\u003e.svg\\\")",
              "type": "string",
              "examples": [
                "modules/cafe-master/assets/brand/logo.svg"
              ]
            },
            "menu": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/MenuItem"
              }
            },
            "modules": {
              "description": "Modules mounted by this App — manifests outside these modules are excluded from the App bundle",
              "type": "array",
              "items": {
                "type": "string"
              },
              "examples": [
                "[clinic, pharmacy]"
              ]
            },
            "page_transition": {
              "description": "Page-to-page navigation animation (View Transitions API), scoped to the page content area: none | fade (default) | slide | slide-up | scale",
              "type": "string",
              "enum": [
                "none",
                "fade",
                "slide",
                "slide-up",
                "scale"
              ],
              "examples": [
                "fade"
              ]
            },
            "persist_backend": {
              "description": "Entity persist backend (backend/04-persist-backend.md), e.g. jsonb-persist",
              "type": "string",
              "examples": [
                "jsonb-persist"
              ]
            },
            "publishes": {
              "description": "cross-app interfaces offered",
              "type": "array",
              "items": {
                "$ref": "#/$defs/AppInterface"
              }
            },
            "registered_views": {
              "description": "Extra views this App exposes beyond its menu: exactly one of entity (module/entity) or view (module/name) per entry",
              "type": "array",
              "items": {
                "$ref": "#/$defs/RegisteredViewDecl"
              },
              "examples": [
                "[{view: cafe-order/menu-catalog}, {entity: cafe-master/menu-item}]"
              ]
            },
            "renderers": {
              "description": "Renderers maps a VisualSpecKind name → renderer for the whole App",
              "type": "object",
              "additionalProperties": {}
            },
            "root_url": {
              "description": "Mount prefix inside the workspace: \\\"/\\\" or any \\\"/path\\\" — unique per workspace; reserved segments (_ui, api, _admin, assets, health, login, register, _ws, print) are rejected",
              "type": "string",
              "examples": [
                "/app/klinik"
              ],
              "pattern": "^(/|/[^/]+(/[^/]+)*)$"
            },
            "stack_family": {
              "description": "Shell implementation (frontend/03-renderer-kind.md), e.g. react-shadcn",
              "type": "string",
              "examples": [
                "react-shadcn"
              ]
            },
            "theme_ref": {
              "description": "Theme kind name applied per-App (frontend/05-app-kinds.md §6)",
              "type": "string",
              "examples": [
                "ocean-blue"
              ]
            },
            "title": {
              "description": "Human-readable display name (spaces allowed) — brand bar + document.title; metadata.name stays the machine identifier",
              "type": "string",
              "examples": [
                "Acme Corp Portal"
              ]
            },
            "vendor": {
              "description": "Vendor is optional — the publishing vendor identity, only required",
              "type": "string",
              "examples": [
                "acme-corp"
              ]
            },
            "version": {
              "description": "Version is optional — only meaningful when publishing the App to the",
              "type": "string",
              "examples": [
                "1.0.0"
              ]
            },
            "workspaces": {
              "description": "Optional workspace mount allowlist — absent = all workspaces; [] = staged (mounted nowhere); [slug,...] = only those workspaces",
              "type": "array",
              "items": {
                "type": "string"
              },
              "examples": [
                "[cafe, kopi]"
              ],
              "nullable": true
            }
          },
          "required": [
            "root_url"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Module"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Module Spec",
          "description": "ModuleSpec defines a package of manifests (Core §4.3, Ref D19).\n",
          "type": "object",
          "properties": {
            "ai_index": {
              "$ref": "#/$defs/AiIndexDecl",
              "description": "AI discovery metadata (ai/04-formspec-remote-mcp.md §3)",
              "nullable": true
            },
            "config": {
              "description": "module-specific configuration (02-workspace-app-module.md §2)",
              "type": "object",
              "additionalProperties": {}
            },
            "datastore": {
              "description": "Datastore binds the module to a named kind: Datastore for ctx.db()",
              "type": "string",
              "examples": [
                "default"
              ]
            },
            "datastores": {
              "description": "Datastores overrides the App-level datastore selection for this module",
              "type": "object",
              "additionalProperties": {},
              "examples": [
                "db: pg-main"
              ]
            },
            "depends": {
              "description": "Module dependencies — array of {module, version?}",
              "type": "array",
              "items": {
                "$ref": "#/$defs/Dependency"
              },
              "examples": [
                "formspec/core"
              ]
            },
            "menu": {
              "description": "Menu is a default navigation suggestion, module-relative (no `Module`",
              "type": "array",
              "items": {
                "$ref": "#/$defs/MenuItem"
              }
            },
            "runtime": {
              "description": "Module runtime binding for sidecar/native execution; local means native compiled-in implementation",
              "type": "string",
              "enum": [
                "local",
                "typescript",
                "node",
                "php",
                "python",
                "go",
                "java",
                "dotnet",
                "ruby",
                "rust"
              ],
              "examples": [
                "local"
              ]
            },
            "vendor": {
              "description": "@schema {example: \"acme-corp\"}",
              "type": "string",
              "examples": [
                "acme-corp"
              ]
            },
            "version": {
              "description": "@schema {example: \"1.0.0\"}",
              "type": "string",
              "examples": [
                "1.0.0"
              ]
            }
          },
          "required": [
            "version"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Entity"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Entity Spec",
          "description": "EntitySpec is the body of a `kind: Entity` manifest.\n\nThere is deliberately no `version` field. One used to exist as a\nrequired-but-unread property — the JSON Schema demanded it, yet\nValidateEntitySpec never looked at it and no runtime path consumed it.\nStorage-shape changes are detected by the migration checksum\n(renderers/jsonb-persist/migrate.go entityChecksum), and the enforced spec\nversion lives in the manifest's `apiVersion`. A field that is always `v1` and\ngates nothing reads as a contract while being decoration, so it was removed\nrather than given a second, weaker meaning.\n",
          "type": "object",
          "properties": {
            "actions": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/Action"
              }
            },
            "assignments": {
              "description": "Assignments declares that this entity records which principal is assigned",
              "type": "array",
              "items": {
                "$ref": "#/$defs/AssignmentDecl"
              }
            },
            "auth": {
              "$ref": "#/$defs/EntityAuth",
              "nullable": true
            },
            "backdate_policy": {
              "$ref": "#/$defs/BackdatePolicy",
              "nullable": true
            },
            "cache": {
              "$ref": "#/$defs/CacheSpec",
              "description": "Cache opts this entity into the framework read-through cache on",
              "nullable": true
            },
            "characteristic": {
              "$ref": "#/$defs/Characteristic",
              "description": "Characteristic is required: it is the axis the engine branches on"
            },
            "create_scope": {
              "description": "CreateScope pins a dimension field on CREATE from a record the payload",
              "type": "array",
              "items": {
                "$ref": "#/$defs/CreateScopeSpec"
              }
            },
            "deliver": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DeliveryDecl"
              }
            },
            "display_field": {
              "description": "@schema {example: \"name\"}",
              "type": "string",
              "examples": [
                "name"
              ]
            },
            "events": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/EventDecl"
              }
            },
            "expose": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/ExposeConfig"
              }
            },
            "extend_storage": {
              "$ref": "#/$defs/ExtendStorage",
              "nullable": true
            },
            "fields": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/Field"
              }
            },
            "forward_date_policy": {
              "$ref": "#/$defs/ForwardDatePolicy",
              "nullable": true
            },
            "hooks": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/HookDecl"
              }
            },
            "indexes": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/IndexDecl"
              }
            },
            "input_sets": {
              "description": "InputSets declares named, reusable lists of action inputs. A transition or",
              "type": "array",
              "items": {
                "$ref": "#/$defs/InputSet"
              }
            },
            "invariants": {
              "description": "Invariants declares properties that must hold for a `characteristic:",
              "type": "array",
              "items": {
                "$ref": "#/$defs/InvariantDecl"
              }
            },
            "join_key": {
              "type": "string"
            },
            "lifecycle": {
              "description": "@schema {example: \"plain_crud\", enum: [\"two_step_autosave\", \"two_step_manual\", \"plain_crud\"]}",
              "type": "string",
              "enum": [
                "two_step_autosave",
                "two_step_manual",
                "plain_crud"
              ],
              "examples": [
                "plain_crud"
              ]
            },
            "maintained_by": {
              "description": "MaintainedBy names the script that keeps a `characteristic: summary`",
              "type": "string"
            },
            "persist": {
              "$ref": "#/$defs/PersistSpec",
              "nullable": true
            },
            "plural": {
              "description": "@schema {example: \"invoices\"}",
              "type": "string",
              "examples": [
                "invoices"
              ]
            },
            "rate_limit": {
              "$ref": "#/$defs/RateLimitSpec",
              "description": "1.4.1 resource-level rate limit (02-core-extended.md §17)",
              "nullable": true
            },
            "rebuild": {
              "$ref": "#/$defs/RebuildSpec",
              "nullable": true
            },
            "row_scope": {
              "description": "RowScope declares the row-level filters the server enforces on every read",
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "scope": {
              "$ref": "#/$defs/ScopeDecl",
              "description": "Scope declares that this entity's rows are partitioned along a named",
              "nullable": true
            },
            "soft_deactivate": {
              "$ref": "#/$defs/SoftDeactivateDecl",
              "description": "1.4.10",
              "nullable": true
            },
            "sources": {
              "description": "Summary-source contract for Entity characteristic: summary (Core Extended",
              "type": "array",
              "items": {
                "$ref": "#/$defs/SummarySource"
              }
            },
            "state_machine": {
              "$ref": "#/$defs/StateMachine",
              "nullable": true
            }
          },
          "required": [
            "characteristic"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Service"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Service Spec",
          "description": "ServiceSpec defines a stateless, pure computation resource (Core §4.2).\n\nLike EntitySpec, there is deliberately no `version`: the enforced spec\nversion is the manifest's `apiVersion`, and an always-`v1` field that no\ncode reads is decoration, not a contract.\n",
          "type": "object",
          "properties": {
            "actions": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/Action"
              }
            },
            "auth": {
              "$ref": "#/$defs/EntityAuth",
              "nullable": true
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Config"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Config Spec",
          "description": "ConfigSpec defines runtime configuration values (Core §4.5, §10).\nKeys are structured — each key declares its type, default value, and\nwhether it is a secret (never inlined in YAML, resolved per environment).\nScripts read values via ctx.config.get(\"key\").\nConfigSpec declares module-level configuration keys (01-core-basic.md §10).\n\n`settings` is the typed, global presentation/config namespace (spec §10 —\n\"jangan pernah menebak\"). It lives in ONE place (workspace/App Config) and\ndrives cross-component interpretation/display: currency, locale, timezone,\ndate format, decimal scale, rounding. Renderers read it instead of guessing.\n",
          "type": "object",
          "properties": {
            "keys": {
              "description": "@schema {example: \"{invoice_due_days: {type: int, default: 30}, smtp_host: {type: string, secret: true}}\"}",
              "type": "object",
              "additionalProperties": {
                "$ref": "#/$defs/ConfigKey"
              },
              "examples": [
                "{invoice_due_days: {type: int, default: 30}, smtp_host: {type: string, secret: true}}"
              ]
            },
            "settings": {
              "$ref": "#/$defs/Settings",
              "description": "Settings is the typed global presentation/config namespace (spec §10).",
              "nullable": true
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Subscription"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Subscription Spec",
          "description": "SubscriptionSpec subscribes to another resource's events (Core §4.6, Ref D35,\n02-core-extended.md §3).\n\nTier 1 (Core, outbox): Events + Handler only.\nTier 2 (Streaming): adds store, retention, position, max_retry, dead_letter,\nfilter, transform, and explicit delivery channel.\n",
          "type": "object",
          "properties": {
            "dead_letter": {
              "$ref": "#/$defs/DeliveryTarget",
              "description": "Tier 2",
              "nullable": true
            },
            "delivery": {
              "$ref": "#/$defs/SubDeliveryDecl",
              "description": "Tier 2: delivery channel",
              "nullable": true
            },
            "durability": {
              "description": "Tier 2: durability mode (\"durable\" = streaming)",
              "type": "string"
            },
            "events": {
              "description": "@schema {example: \"billing.invoice.on_submit\"}",
              "type": "array",
              "items": {
                "type": "string"
              },
              "examples": [
                "billing.invoice.on_submit"
              ]
            },
            "filter": {
              "description": "Tier 2: Starlark filter over event payload",
              "type": "string"
            },
            "handler": {
              "$ref": "#/$defs/ImplDecl"
            },
            "max_retry": {
              "description": "Tier 2",
              "type": "integer"
            },
            "position": {
              "description": "@schema {example: \"latest\", enum: [\"latest\", \"earliest\"]}",
              "type": "string",
              "enum": [
                "latest",
                "earliest"
              ],
              "examples": [
                "latest"
              ]
            },
            "retention": {
              "description": "Tier 2: stream retention duration",
              "type": "string"
            },
            "retry": {
              "$ref": "#/$defs/RetryDecl",
              "description": "Tier 2",
              "nullable": true
            },
            "store": {
              "description": "@schema {example: \"redis\"}",
              "type": "string",
              "examples": [
                "redis"
              ]
            },
            "transform": {
              "description": "Tier 2: Starlark transform over event payload",
              "type": "string"
            },
            "uses": {
              "$ref": "#/$defs/UsesDecl",
              "description": "Uses declares what the HANDLER may touch — the same shape and the same",
              "nullable": true
            }
          },
          "required": [
            "handler"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Api"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Api Spec",
          "description": "ApiSpec overrides the external API surface (/api/v1/) for a module's entities\n(02-core-extended.md §12). It does not affect the UI surface (/_ui/entity/).\n",
          "type": "object",
          "properties": {
            "grpc": {
              "$ref": "#/$defs/ApiGRPCConfig",
              "nullable": true
            },
            "rest": {
              "$ref": "#/$defs/ApiRESTConfig",
              "nullable": true
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Webhook"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Webhook Spec",
          "description": "WebhookSpec defines a verified inbound webhook endpoint\n(02-core-extended.md §4).\n",
          "type": "object",
          "properties": {
            "auth": {
              "$ref": "#/$defs/WebhookAuth",
              "nullable": true
            },
            "for": {
              "description": "@schema {example: \"billing.invoice\"}",
              "type": "string",
              "examples": [
                "billing.invoice"
              ]
            },
            "idempotency_key": {
              "$ref": "#/$defs/IdempotencyDecl",
              "nullable": true
            },
            "idempotent": {
              "type": "boolean"
            },
            "method": {
              "description": "@schema {example: \"POST\", enum: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"]}",
              "type": "string",
              "enum": [
                "GET",
                "POST",
                "PUT",
                "PATCH",
                "DELETE"
              ],
              "examples": [
                "POST"
              ]
            },
            "path": {
              "description": "@schema {example: \"/webhooks/midtrans\"}",
              "type": "string",
              "examples": [
                "/webhooks/midtrans"
              ]
            }
          },
          "required": [
            "for",
            "method",
            "auth"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Integrator"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Integrator Spec",
          "description": "IntegratorSpec bridges two entities/modules that do not know each other\ndirectly (02-core-extended.md §5).\n",
          "type": "object",
          "properties": {
            "call": {
              "$ref": "#/$defs/IntegratorCall",
              "nullable": true
            },
            "compensate": {
              "description": "@schema {example: \"gl.journal-entry.cancel\"}",
              "type": "string",
              "examples": [
                "gl.journal-entry.cancel"
              ]
            },
            "listen": {
              "$ref": "#/$defs/IntegratorListen",
              "nullable": true
            }
          },
          "required": [
            "listen",
            "call"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Mockup"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Mockup Spec",
          "description": "MockupSpec defines a simulated connector that implements the same contract\nas the real integration (02-core-extended.md §8).\n",
          "type": "object",
          "properties": {
            "config_ref": {
              "type": "string"
            },
            "for": {
              "description": "@schema {example: \"billing.payment-gateway\"}",
              "type": "string",
              "examples": [
                "billing.payment-gateway"
              ]
            }
          },
          "required": [
            "for"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "KindDefinition"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "KindDefinition Spec",
          "description": "KindDefinitionSpec declares a new resource kind (CRD-like extension),\nincluding its schema and handler (platform/03-kind-system.md §2).\n",
          "type": "object",
          "properties": {
            "group": {
              "description": "Group names the kind's namespace (CRD-style, e.g. \"seed.formspec.dev\") —",
              "type": "string",
              "examples": [
                "seed.formspec.dev"
              ]
            },
            "handler": {
              "$ref": "#/$defs/ImplDecl",
              "nullable": true
            },
            "schema": {},
            "scope": {
              "description": "@schema {example: \"module\", enum: [\"module\", \"app\"]}",
              "type": "string",
              "enum": [
                "module",
                "app"
              ],
              "examples": [
                "module"
              ]
            }
          },
          "required": [
            "group",
            "handler"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Environment"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Environment Spec",
          "description": "EnvironmentSpec defines one deployment target (platform/04-control-plane.md §2).\n",
          "type": "object",
          "properties": {
            "key_ref": {
              "description": "KeyRef is the location of the platform signing key (e.g. kms://prod-signing).",
              "type": "string",
              "examples": [
                "kms://prod-signing"
              ]
            },
            "mode": {
              "$ref": "#/$defs/EnvironmentMode",
              "description": "Mode is the deployment environment mode — dev | prod."
            },
            "policy": {
              "description": "Policy names the kind: Policy that applies to this environment.",
              "type": "string"
            },
            "resource_planes": {
              "description": "ResourcePlanes lists the resource plane endpoints for this environment.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/EnvironmentPlane"
              }
            },
            "resource_pool": {
              "description": "Resource pool strategy",
              "type": "string",
              "enum": [
                "shared",
                "exclusive"
              ],
              "examples": [
                "shared"
              ]
            },
            "tier": {
              "description": "Deployment tier",
              "type": "string",
              "enum": [
                "standalone",
                "cloud",
                "enterprise"
              ],
              "examples": [
                "cloud"
              ]
            }
          },
          "required": [
            "mode",
            "tier",
            "resource_pool",
            "key_ref",
            "policy"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Policy"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Policy Spec",
          "description": "PolicySpec defines governance rules evaluated on control-plane decisions\n(platform/04-control-plane.md §5). The escape hatch `rego` is compiled into\nthe same OPA evaluation engine as the structured vocabulary.\n",
          "type": "object",
          "properties": {
            "blocked": {
              "description": "Blocked is the policy floor — rules that cannot be configured away.",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "rego": {
              "description": "Rego is the escape hatch — full OPA policy body.",
              "type": "string"
            },
            "require_approval": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/PolicyApproval"
              }
            },
            "require_signing": {
              "type": "boolean"
            },
            "require_staging_first": {
              "type": "boolean"
            }
          },
          "required": [
            "require_signing",
            "require_staging_first"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Datastore"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Datastore Spec",
          "description": "DatastoreSpec is the spec body for kind: Datastore.\n",
          "type": "object",
          "properties": {
            "access": {
              "$ref": "#/$defs/DatastoreAccess",
              "description": "Access controls who (filter) can use this datastore and what",
              "nullable": true
            },
            "connection": {
              "$ref": "#/$defs/DatastoreConnection",
              "description": "Connection holds connection parameters for the backend."
            },
            "credential_ref": {
              "description": "CredentialRef is a reference to KMS/Vault for credentials.",
              "type": "string",
              "examples": [
                "kms://workspace-default"
              ]
            },
            "driver": {
              "$ref": "#/$defs/DatastoreDriver",
              "description": "Driver identifies the backend technology."
            },
            "serves": {
              "description": "Serves lists which ctx.* primitives this datastore backs.",
              "type": "array",
              "items": {
                "$ref": "#/$defs/PrimitiveType"
              },
              "examples": [
                "[db]"
              ]
            }
          },
          "required": [
            "driver",
            "connection"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Workspace"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Workspace Spec",
          "description": "WorkspaceSpec is the kind-specific body of a `kind: Workspace` manifest.\n",
          "type": "object",
          "properties": {
            "description": {
              "description": "Description explains the workspace's purpose (AI readability).",
              "type": "string",
              "examples": [
                "Workspace utama aplikasi kafe demo"
              ]
            },
            "display_name": {
              "description": "Human-readable workspace name — shown in admin surfaces",
              "type": "string",
              "examples": [
                "Kafe Demo"
              ]
            },
            "owner_user_id": {
              "description": "Optional user ID seeded as workspace owner — empty = no seeded owner (first admin via setup wizard)",
              "type": "string"
            },
            "settings": {
              "description": "Free-form workspace metadata persisted to the registry row (json) — structured platform settings belong to kind: Config",
              "type": "object",
              "additionalProperties": {}
            },
            "slug": {
              "description": "URL-facing workspace slug — defaults to metadata.name; kebab-case, unique across the deployment",
              "type": "string",
              "examples": [
                "cafe"
              ],
              "pattern": "^[a-z0-9](-[a-z0-9])*$"
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Seed"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Seed Spec",
          "description": "SeedSpec is the kind-specific body of a `kind: Seed` manifest.\n",
          "type": "object",
          "properties": {
            "entities": {
              "description": "Entities declares records for one or more entities, grouped so a reader",
              "type": "array",
              "items": {
                "$ref": "#/$defs/SeedEntity"
              }
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Renderer"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Renderer Spec",
          "description": "RendererSpec declares a concrete implementation of a VisualSpecKind\n(frontend/03-renderer-kind.md).\n",
          "type": "object",
          "properties": {
            "implements": {
              "description": "@schema {example: \"formspec/visual.form-page\"}",
              "type": "string",
              "examples": [
                "formspec/visual.form-page"
              ]
            },
            "stack_family": {
              "description": "@schema {example: \"react-shadcn\"}",
              "type": "string",
              "examples": [
                "react-shadcn"
              ]
            },
            "trust_tier": {
              "description": "@schema {example: \"official\", enum: [\"official\", \"verified\", \"community\"]}",
              "type": "string",
              "enum": [
                "official",
                "verified",
                "community"
              ],
              "examples": [
                "official"
              ]
            }
          },
          "required": [
            "implements",
            "stack_family",
            "trust_tier"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "PersistBackend"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "PersistBackend Spec",
          "description": "PersistBackendSpec declares a storage seam implementation\n(backend/04-persist-backend.md).\n",
          "type": "object",
          "properties": {
            "implements": {
              "description": "@schema {example: \"formspec/storage.entity-persist\"}",
              "type": "string",
              "examples": [
                "formspec/storage.entity-persist"
              ]
            },
            "trust_tier": {
              "description": "@schema {example: \"official\", enum: [\"official\", \"verified\", \"community\"]}",
              "type": "string",
              "enum": [
                "official",
                "verified",
                "community"
              ],
              "examples": [
                "official"
              ]
            }
          },
          "required": [
            "implements",
            "trust_tier"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Page"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Page Spec",
          "description": "PageSpec defines a routed screen composing blocks (Frontend §3).\n`blocks` and `tabs` are mutually exclusive; `mode: custom` excludes both.\n",
          "type": "object",
          "properties": {
            "asset": {
              "description": "Asset is the spec-root-relative asset path for `mode: custom`",
              "type": "string"
            },
            "binds": {
              "$ref": "#/$defs/PageBinds",
              "description": "Binds is the backend footprint (entities/actions/subscribe) a custom",
              "nullable": true
            },
            "blocks": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/PageBlock"
              }
            },
            "context": {
              "description": "Context declares render-context variables injected into this page's",
              "type": "array",
              "items": {
                "$ref": "#/$defs/ContextDecl"
              }
            },
            "description": {
              "type": "string"
            },
            "icon": {
              "type": "string"
            },
            "layout": {
              "$ref": "#/$defs/PageLayout",
              "nullable": true
            },
            "mode": {
              "description": "Page mode. `custom` hands all rendering to an asset component; empty means blocks/tabs composition.",
              "type": "string",
              "enum": [
                "",
                "custom"
              ]
            },
            "permissions": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "public": {
              "description": "If true (default), a route is generated for this page. Set false to restrict to embedding only.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "renderer": {
              "description": "Renderer is the per-instance renderer override (frontend/03-renderer-",
              "type": "string"
            },
            "route": {
              "description": "@schema {example: \"/orders/:id\"}",
              "type": "string",
              "examples": [
                "/orders/:id"
              ]
            },
            "tabs": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/PageTab"
              }
            },
            "title": {
              "description": "@schema {example: \"Order {order.number}\"}",
              "type": "string",
              "examples": [
                "Order {order.number}"
              ]
            },
            "title_visible": {
              "description": "Render the page title heading (default true)",
              "type": "boolean",
              "nullable": true
            }
          },
          "required": [
            "route",
            "title"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Form"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Form Spec",
          "description": "FormSpec defines an input/edit layout (Frontend §4).\n",
          "type": "object",
          "properties": {
            "actions": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FormAction"
              }
            },
            "auth_action": {
              "description": "Bind submit to a platform auth action (mutually exclusive with entity).",
              "type": "string",
              "enum": [
                "login",
                "register",
                "change_password",
                "forgot_password",
                "reset_password"
              ]
            },
            "confirm": {
              "$ref": "#/$defs/FormConfirm",
              "description": "Confirm overrides the App-level confirm defaults for this form",
              "nullable": true
            },
            "context": {
              "description": "Context declares render-context variables injected into this form's",
              "type": "array",
              "items": {
                "$ref": "#/$defs/ContextDecl"
              }
            },
            "entity": {
              "description": "@schema {example: \"billing.order\"}",
              "type": "string",
              "examples": [
                "billing.order"
              ]
            },
            "mode": {
              "description": "@schema {example: \"edit\", enum: [\"create\", \"edit\", \"view\"]}",
              "type": "string",
              "enum": [
                "create",
                "edit",
                "view"
              ],
              "examples": [
                "edit"
              ]
            },
            "public": {
              "description": "If true (default), a route /module/form/\u003cname\u003e is auto-generated. Set false for embed-only forms.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "render": {
              "$ref": "#/$defs/FormRenderDecl",
              "nullable": true
            },
            "sections": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FormSection"
              }
            },
            "submit": {
              "$ref": "#/$defs/FormSubmit",
              "nullable": true
            }
          },
          "required": [
            "entity"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Table"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Table Spec",
          "description": "TableSpec defines a list/browse view (Frontend §5).\n",
          "type": "object",
          "properties": {
            "batch_edit": {
              "description": "Batch editing: fields editable across a multi-row selection. Framework runs update per row, partial failure reported per row.",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "bulk_actions": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TableAction"
              }
            },
            "columns": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TableColumn"
              }
            },
            "default_sort": {
              "description": "@schema {example: \"-created_at\"}",
              "type": "string",
              "examples": [
                "-created_at"
              ]
            },
            "entity": {
              "description": "@schema {example: \"billing.order\"}",
              "type": "string",
              "examples": [
                "billing.order"
              ]
            },
            "filters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "fixed_filters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "page_size": {
              "type": "integer"
            },
            "public": {
              "description": "If true (default), a route /module/table/\u003cname\u003e is auto-generated. Set false for embed-only tables.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "realtime": {
              "type": "boolean"
            },
            "row_actions": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TableAction"
              }
            },
            "search": {
              "type": "boolean"
            }
          },
          "required": [
            "entity"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Dashboard"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Dashboard Spec",
          "description": "DashboardSpec defines a widget canvas (Frontend §5).\n",
          "type": "object",
          "properties": {
            "customizable": {
              "type": "boolean"
            },
            "defaults": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": {
              "type": "string"
            },
            "public": {
              "description": "If true (default), a route /module/dashboard/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "realtime": {
              "type": "boolean"
            },
            "refresh": {
              "type": "integer"
            },
            "title": {
              "type": "string"
            },
            "widgets": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/DashboardWidget"
              }
            }
          },
          "required": [
            "title"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Widget"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Widget Spec",
          "description": "WidgetSpec defines a reusable dashboard widget (Frontend §5).\n",
          "type": "object",
          "properties": {
            "config": {
              "type": "object",
              "additionalProperties": {}
            },
            "entity": {
              "description": "@schema {example: \"sales-daily-summary\"}",
              "type": "string",
              "examples": [
                "sales-daily-summary"
              ]
            },
            "public": {
              "description": "If true (default), a route /module/widget/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "query": {
              "type": "string"
            },
            "refresh_secs": {
              "type": "integer"
            },
            "size": {
              "$ref": "#/$defs/WidgetLayout",
              "nullable": true
            },
            "title": {
              "description": "@schema {example: \"Today's Revenue\"}",
              "type": "string",
              "examples": [
                "Today's Revenue"
              ]
            },
            "type": {
              "description": "@schema {example: \"metric\", enum: [\"metric\", \"chart\", \"table\", \"list\"]}",
              "type": "string",
              "enum": [
                "metric",
                "chart",
                "table",
                "list"
              ],
              "examples": [
                "metric"
              ]
            }
          },
          "required": [
            "title",
            "type"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Report"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Report Spec",
          "description": "ReportSpec defines a parameterized tabular report (Frontend §5).\n",
          "type": "object",
          "properties": {
            "columns": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/ReportColumn"
              }
            },
            "entity": {
              "description": "@schema {example: \"billing.order\"}",
              "type": "string",
              "examples": [
                "billing.order"
              ]
            },
            "export": {
              "description": "pdf | csv | xlsx",
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "groups": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/ReportGroup"
              }
            },
            "parameters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/ReportParam"
              }
            },
            "public": {
              "description": "If true (default), a route /module/report/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "required_permission": {
              "type": "string"
            },
            "source": {
              "$ref": "#/$defs/ReportSource",
              "description": "Source is the declarative parameterized filter (06-page-kinds.md §8",
              "nullable": true
            },
            "title": {
              "description": "@schema {example: \"Sales by Category\"}",
              "type": "string",
              "examples": [
                "Sales by Category"
              ]
            },
            "totals": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/ReportTotal"
              }
            }
          },
          "required": [
            "title",
            "entity"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Wizard"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Wizard Spec",
          "description": "WizardSpec defines a multi-step business process (Frontend §11).\n",
          "type": "object",
          "properties": {
            "action": {
              "description": "server action that commits all steps; if empty, final step plain-creates Entity",
              "type": "string"
            },
            "entity": {
              "description": "@schema {example: \"clinic.visit\"}",
              "type": "string",
              "examples": [
                "clinic.visit"
              ]
            },
            "on_complete": {
              "$ref": "#/$defs/WizardOnComplete",
              "nullable": true
            },
            "public": {
              "description": "If true (default), a route /module/wizard/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "steps": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/WizardStep"
              }
            },
            "title": {
              "type": "string"
            }
          },
          "required": [
            "title"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Kanban"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Kanban Spec",
          "description": "KanbanSpec defines a drag-and-drop status board (Frontend §12).\n",
          "type": "object",
          "properties": {
            "card_template": {
              "$ref": "#/$defs/KanbanCard",
              "nullable": true
            },
            "columns": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/KanbanColumn"
              }
            },
            "drag_guard": {
              "description": "FormSpecExpr pre-check UX before drop: evaluated against the record + target column; drop blocked when false. Server state-machine guard remains authority.",
              "type": "string"
            },
            "entity": {
              "description": "@schema {example: \"helpdesk.ticket\"}",
              "type": "string",
              "examples": [
                "helpdesk.ticket"
              ]
            },
            "filters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "fixed_filters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "max_cards_per_column": {
              "type": "integer"
            },
            "position_field": {
              "description": "field storing user-adjustable position (e.g. \"queue_position\")",
              "type": "string"
            },
            "public": {
              "description": "If true (default), a route /module/kanban/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "realtime": {
              "description": "default true (§12)",
              "type": "boolean",
              "nullable": true
            },
            "row_actions": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TableAction"
              }
            },
            "search": {
              "type": "boolean"
            },
            "sortable": {
              "description": "enable within-column drag-to-reorder",
              "type": "boolean"
            },
            "status_field": {
              "description": "@schema {example: \"status\"}",
              "type": "string",
              "examples": [
                "status"
              ]
            }
          },
          "required": [
            "entity",
            "status_field"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Timeline"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Timeline Spec",
          "description": "TimelineSpec defines a chronological event journal (Frontend §13).\n",
          "type": "object",
          "properties": {
            "bind_param": {
              "type": "string"
            },
            "bind_value": {
              "type": "string"
            },
            "date_field": {
              "type": "string"
            },
            "display": {
              "$ref": "#/$defs/TimelineDisplay",
              "nullable": true
            },
            "empty_state": {
              "type": "string"
            },
            "entity": {
              "description": "@schema {example: \"clinic.medical_record\"}",
              "type": "string",
              "examples": [
                "clinic.medical_record"
              ]
            },
            "event_field": {
              "type": "string"
            },
            "group_by": {
              "description": "date | month | year | none",
              "type": "string"
            },
            "page_size": {
              "type": "integer"
            },
            "public": {
              "description": "If true (default), a route /module/timeline/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "realtime": {
              "description": "Realtime refetches the timeline on its entity's mutation events.",
              "type": "boolean"
            },
            "sort": {
              "description": "asc | desc (default desc)",
              "type": "string"
            }
          },
          "required": [
            "entity"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Print"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Print Spec",
          "description": "PrintSpec defines a printable document template (Frontend §9).\nOne format per manifest — declared via `output.format` (Frontend §9).\n",
          "type": "object",
          "properties": {
            "asset": {
              "description": "Asset is the spec-root-relative asset path for a document whose markup the",
              "type": "string"
            },
            "binds": {
              "$ref": "#/$defs/PageBinds",
              "description": "Binds is the backend footprint (entities/actions/subscribe) an",
              "nullable": true
            },
            "body": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/PrintBodyItem"
              }
            },
            "entity": {
              "description": "@schema {example: \"billing.order\"}",
              "type": "string",
              "examples": [
                "billing.order"
              ]
            },
            "footer": {
              "$ref": "#/$defs/PrintFooter",
              "nullable": true
            },
            "header": {
              "$ref": "#/$defs/PrintHeader",
              "nullable": true
            },
            "output": {
              "$ref": "#/$defs/PrintOutput",
              "nullable": true
            },
            "public": {
              "description": "If true (default), a route /module/print/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "template": {
              "type": "string"
            }
          },
          "required": [
            "entity"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Theme"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Theme Spec",
          "description": "ThemeSpec defines look \u0026 feel as a distributable artifact (Frontend §10).\n",
          "type": "object",
          "properties": {
            "public": {
              "description": "If true (default), the theme is active and published in the bundle.",
              "type": "boolean",
              "nullable": true
            },
            "stylesheet": {
              "type": "string"
            },
            "tokens": {
              "type": "object",
              "additionalProperties": {}
            },
            "widgets": {
              "description": "base widget → asset skin",
              "type": "object",
              "additionalProperties": {}
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Calendar"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Calendar Spec",
          "description": "CalendarSpec defines a calendar view for date/datetime entity data\n(06-page-kinds.md §5). Instance of VisualSpecKind tier: page.\n",
          "type": "object",
          "properties": {
            "color_field": {
              "type": "string"
            },
            "date_field": {
              "description": "@schema {example: \"scheduled_at\"}",
              "type": "string",
              "examples": [
                "scheduled_at"
              ]
            },
            "end_field": {
              "type": "string"
            },
            "entity": {
              "description": "@schema {example: \"clinic.appointment\"}",
              "type": "string",
              "examples": [
                "clinic.appointment"
              ]
            },
            "public": {
              "description": "If true (default), a route /module/calendar/\u003cname\u003e is auto-generated.",
              "type": "boolean",
              "examples": [
                "true"
              ],
              "nullable": true
            },
            "realtime": {
              "type": "boolean"
            },
            "resource_field": {
              "type": "string"
            },
            "title_field": {
              "type": "string"
            },
            "views": {
              "description": "month, week, day, resource (default month)",
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "required": [
            "entity",
            "date_field"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "Listing"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "Listing Spec",
          "description": "ListingSpec defines a public catalog page (06-page-kinds.md §10).\nInstance of VisualSpecKind tier: page. Similar to table-list but without\nAuth-wrap assumptions and without row_actions/bulk_actions.\n",
          "type": "object",
          "properties": {
            "columns": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TableColumn"
              }
            },
            "entity": {
              "description": "@schema {example: \"shop.product\"}",
              "type": "string",
              "examples": [
                "shop.product"
              ]
            },
            "filters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "search": {
              "type": "boolean"
            }
          },
          "required": [
            "entity"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "ApprovalInbox"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "ApprovalInbox Spec",
          "description": "ApprovalInboxSpec defines the pending-approval task queue page\n(06-page-kinds.md §11). Instance of VisualSpecKind tier: page.\nZero-config: sources are pending Workflow steps eligible for the caller.\n",
          "type": "object",
          "properties": {
            "filters": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/FilterSpec"
              }
            },
            "realtime": {
              "type": "boolean"
            },
            "search": {
              "type": "boolean"
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "NotificationCenter"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "NotificationCenter Spec",
          "description": "NotificationCenterSpec defines the in-app notification page\n(06-page-kinds.md §12). Instance of VisualSpecKind tier: page.\nZero-config: lists caller's notifications from formspec/notify.\n",
          "type": "object",
          "properties": {
            "realtime": {
              "type": "boolean"
            }
          },
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    },
    {
      "properties": {
        "apiVersion": {
          "type": "string",
          "const": "formspec.dev/v1"
        },
        "kind": {
          "type": "string",
          "const": "VisualSpecKind"
        },
        "metadata": {
          "description": "Metadata is common to all FormSpec resources.\n",
          "type": "object",
          "properties": {
            "annotations": {
              "type": "object",
              "additionalProperties": {}
            },
            "description": {
              "type": "string"
            },
            "labels": {
              "type": "object",
              "additionalProperties": {}
            },
            "module": {
              "type": "string"
            },
            "name": {
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "additionalProperties": false
        },
        "spec": {
          "title": "VisualSpecKind Spec",
          "description": "VisualSpecKindSpec declares a new view type — a meta-kind that defines the\nschema and renderer contract for a family of page/component instances\n(frontend/02-visual-spec-kind.md).\n",
          "type": "object",
          "properties": {
            "accepts_slots": {
              "description": "tier: page/app only",
              "type": "array",
              "items": {
                "$ref": "#/$defs/SlotDecl"
              }
            },
            "implements_slot": {
              "description": "tier: component only",
              "type": "string"
            },
            "renderer_contract": {},
            "schema": {
              "description": "JSON Schema for instance spec"
            },
            "tier": {
              "description": "app | page | component",
              "type": "string"
            }
          },
          "required": [
            "tier"
          ],
          "additionalProperties": false
        }
      },
      "required": [
        "apiVersion",
        "kind",
        "metadata",
        "spec"
      ]
    }
  ]
}