Private Preview - features may change without notice
GramSpec
Free Allowance →
v1.1 July 2026

GRAM Specification

The formal standard for Graph-Rule Analytical Mapping — deterministic machine-reasoning over relational structures.

Supersedes v1.0 (March 2026)  ·  Status: Draft  ·  Category: Technical Specification  ·  Author: Edward Kench  ·  GitHub  ·  PDF  ·  DOI: 10.5281/zenodo.19037879

Abstract

Large language models are increasingly employed for text-to-SQL generation, yet they operate on SQL Data Definition Language (DDL)—physical metadata that describes how data is stored, not what it means. This forces the model to infer join semantics, cardinality, participation constraints, and column roles from naming conventions alone, a process that is the primary source of errors in generated SQL.

This document defines the GRAM Specification (v1.1)—a formal standard for representing relational database schemas as collections of Asserted Predicates rather than physical storage descriptors. Grounded in Object-Role Modeling (Halpin, 2006) and formalized with predicate calculus, GRAM (Graph-Rule Analytical Mapping) provides a semantic layer that captures an organization’s unique business grammar—the rules, relationships, and vocabulary that define how its data means what it means—bridging the gap between physical DDL and the conceptual schema required for deterministic machine reasoning.

By formalizing entities, fact types, reference schemes, functional dependencies, existence constraints, data types, enumerated domains, alternate readings, sample values, and role names as first-class citizens of the schema, the GRAM specification enables large language models and automated systems to determine correct join semantics, column operations, and domain boundaries without inferential guesswork. Eliminating structural inference from the reasoning pipeline reduces the error surface to semantic misinterpretation alone, removing the class of errors caused by ambiguous join paths, missing cardinality information, and unnamed foreign key relationships.

Version 1.1 distinguishes the two layers at which a GRAM schema is consumed. For machine consumers, the operationally load-bearing content is the constraint modality—uniqueness, mandatoriness, and the cardinality classification they jointly determine—together with role-level identifiers; empirical evaluation (Kench, 2026) shows the lexical content of the predicate verb to be operationally inert when role-level lexical signal is present. Predicate verbalization is the pedagogical layer: the medium of authorship, domain-expert validation, and conceptual-stage modeling. The two layers are formalized as the conformance classes GRAM-Conceptual and GRAM-Physical (Section 8).

Changes in v1.1: conformance classes (GRAM-Conceptual / GRAM-Physical) with a document envelope declaring gramVersion and stage; normative role order; Section 3.3 revised per the lexical-independence result (Kench, 2026), with a new Section 3.4 on operational vs. pedagogical semantics; role aliases (Section 2.12); composite reference schemes and role names; DateTime and Integer data types; enumerations reframed as cached empirical snapshots; namespace-qualified references; named deferrals (Section 9).

1. Introduction: The Semantic Gap

Modern large language models (LLMs) exhibit systematic failure in text-to-SQL tasks because SQL Data Definition Language (DDL) constitutes physical metadata: it describes how data is stored, not what it means. A column definition such as CustomerID INT NOT NULL is a physical constraint. It provides no semantic information about the role that CustomerID plays in the business domain.

GRAM addresses this deficiency by representing a database as a collection of Fact Types (binary relations expressed as natural-language readings) augmented with formally defined constraints. This representation allows an LLM to read the schema rather than infer it, moving from stochastic interpretation to deterministic reasoning.

2. Definitions and Notation

2.1 Entities and Value Types

Let \mathcal{E} denote the set of all Entity Types and \mathcal{V} denote the set of all Value Types. An Entity Type represents a non-value object in the domain (e.g., Employee, Order). A Value Type represents a terminal property (e.g., FirstName, OrderDate).

An Entity Type may optionally carry a namespace that represents the database schema qualifier (e.g., dbo, Sales). When present, the fully-qualified table name is namespace.name. Two entities sharing the same name but differing in namespace are considered distinct types.

2.2 Fact Types

A Fact Type is a binary relation R defined by a predicate P over two participants:

$$R = \{ (e_1, e_2) \mid P(e_1, e_2) \text{ is True} \}$$

where e_i \in (\mathcal{E} \cup \mathcal{V}). The GRAM specification normatively defines binary fact types (arity 2), which represent relationships between two participants expressed as natural-language readings (e.g., "Employee handles Order"). This includes both entity-to-entity relationships and entity-to-value-type properties (e.g., "Employee has FirstName"). These readings constitute the business grammar of the domain—the precise vocabulary and sentence structures through which the organization’s data tells its own story.

Each specific instance in the database, a tuple, is a formal assertion that the predicate defined by the Reading is true for a given pair of participants.

2.3 Roles

Each participant in a Fact Type occupies a Role. A role binds an entity or value type to a specific position within the predicate. Roles carry constraint metadata (uniqueness, mandatoriness) that governs the logical behavior of the relation.

Role order is normative. The order of the roles array in the serialization binds each role to its position in the reading: the first role is the subject of the reading, the second its object. For most fact types the binding is also recoverable from entityName; for fact types in which both roles bind the same entity type (e.g., "Project is sub-project of Project"), array order and roleName are the only distinguishing signals, and reversing the array silently inverts the direction of every constraint on the relation. Consumers must not reorder roles.

Role references are qualified where ambiguous. A role’s entityName (and any dot-notation reference in a derived formula, Section 2.10) must use the fully-qualified namespace.name form whenever the bare name is shared by entities in more than one namespace (Section 2.1).

2.4 Reference Schemes

A Reference Scheme defines how instances of an entity type are uniquely identified. It is the preferred identifier, analogous to a primary key in a relational database. Formally, for each entity type E \in \mathcal{E}, the reference scheme defines an injective function:

$$\text{ref}: E \to D_{\text{id}} \quad \text{such that } \forall a, b \in E : \text{ref}(a) = \text{ref}(b) \implies a = b$$

where D_{\text{id}} is the identifier domain (e.g., integer employee numbers, string codes). In a GRAM-compliant schema, the reference scheme is declared using the notation Employee(empId), rendering as (empId) beneath the entity name on the diagram.

Each entity has exactly one reference scheme. Additional attributes requiring uniqueness (e.g., email address) are modeled as separate fact types with uniqueness constraints, making them alternate keys.

A reference scheme may be composite. When an entity’s preferred identifier spans multiple columns (e.g., an OrderDetail table keyed by OrderId and ProductId), referenceScheme is declared as a single comma-delimited string of column names in key order: "referenceScheme": "orderId,productId". The comma is the normative delimiter; consumers split on it to recover the ordered column list. (A physical column name containing a comma is not representable; such names are pathological in SQL and out of scope.) A composite reference scheme propagates to every referencing role: the foreign key that references a composite key is itself composite, and the corresponding roleName, where declared, is a comma-delimited string aligned position-by-position with the reference scheme (Section 2.9). A consumer generating a join over a composite key must emit an equality predicate for every aligned column pair.

The reference scheme is critical for machine reasoning: it tells an LLM which column to use in JOIN ON clauses and WHERE filters. Without it, the model must guess from column names whether EmpID, EmployeeNumber, or EmpCode is the correct join key.

2.5 Data Types

Value types in the GRAM specification carry an explicit valueDataType property that declares the semantic data category. The specification defines seven normative data types:

Data Type SQL Affinity LLM Significance
TextVARCHAR / NVARCHARString comparison, LIKE patterns, concatenation
NumberDECIMAL / FLOATGeneral numeric: SUM, AVG, arithmetic, ORDER BY numeric
IntegerINT / BIGINTCounts and whole quantities; integer division truncates—CAST before computing ratios
DateDATECalendar dates without a time component: date functions, BETWEEN, DATEADD/DATEDIFF
DateTimeDATETIME / DATETIME2Points in time: BETWEEN requires end-of-day boundary handling; daily grouping requires a CAST to date
BooleanBITPredicate filtering (WHERE IsActive = 1)
CurrencyMONEY / DECIMALSUM, AVG with monetary formatting, rounding rules

DDL alone forces an LLM to infer column semantics from names like amt or dt. The explicit data type eliminates this inference, enabling the model to select appropriate SQL functions and aggregation strategies.

Integer and DateTime (new in v1.1) exist because their absence produces silent wrong answers rather than errors: integer division truncates a ratio to zero without complaint, and a BETWEEN ending on a date boundary silently drops every intra-day row of the final day. Number remains valid for any numeric column and Date for any temporal one—v1.0 documents remain conformant; the new types are refinements a producer should emit when the underlying column warrants them.

2.6 Enumerated Types

An Enumerated Type declares a closed set of allowed values for an object type. The GRAM specification supports enumeration on both value types and entity types, serving distinct purposes.

Value type enums constrain terminal properties. The enumerated values define the complete domain of a column. For example, an OrderStatus value type with values {Pending, Shipped, Delivered} tells the LLM the exact set of valid filter values for status queries.

Entity type enums are closed-world assertions on entities that participate in relationships. For example, a Department entity with values {Engineering, Marketing, Sales, HR} is not merely a constrained string; it is a first-class entity referenced by other facts (e.g., "Employee works for Department", "Department has Budget"). The enumeration tells the LLM that there are exactly four departments, enabling precise WHERE ... IN (...) clauses and exhaustive groupings.

In both cases, the complete set of allowed values is exported in the schema as enumValues, providing the LLM with a closed-world guarantee rather than an open-ended guess.

Declared enumerations are a cached empirical snapshot, not an immutable truth. The authoritative domain of a column is the data itself, and agentic consumers with query access should prefer live inspection (e.g., SELECT DISTINCT) where available. The declared enumeration earns its place in two situations that empirical inspection cannot serve: absent-member queries (“departments with no orders this month”—members with zero rows never appear in a scan of the fact data), and non-probing consumers (single-shot generation without database access, for which enumValues is the only closed-world knowledge available). Producers should treat declared enumerations as subject to drift and revalidate them against the live domain.

2.7 Alternate Readings

An Alternate Reading is an additional natural-language phrasing of the same fact type. While the primary reading and inverse reading define the canonical predicate, alternate readings provide synonymous expressions that increase the surface area for question-to-relation matching.

For example, a fact type with primary reading "Order has OrderDetail" might carry an alternate reading "Order contains OrderDetail." When an LLM receives a user question referencing "line items contained in an order," the alternate reading provides a direct lexical match that the primary reading alone would not.

Alternate readings are purely semantic metadata. They do not alter the relational structure, constraints, or role bindings. They are exported as an array of strings alongside the primary and inverse readings.

2.8 Sample Values

Sample Values are concrete example instances attached to an entity type (e.g., "Acme Corp", "Globex Inc" for a Company entity). They are exported in the schema as sampleValues.

Sample values serve two purposes for downstream reasoning:

  • Disambiguation: They clarify what an entity represents in the real world. An entity named Item could be a product, a menu item, or an invoice line. Sample values like "Widget A", "Gizmo Pro" immediately resolve the ambiguity.
  • Query grounding: When an LLM generates example queries or validates output, concrete values provide realistic test data without requiring database access.

2.9 Role Names

A Role Name is an explicit override for the foreign key column name produced when a binary fact type maps to a relational schema. Ordinarily, when entity B is referenced from entity A's table, the FK column is named after B's referenceScheme. A role name replaces this default:

$$\text{FK column} = \begin{cases} \text{roleName} & \text{if declared} \\ B.\text{referenceScheme} & \text{otherwise} \end{cases}$$

In the JSON serialization, the roleName property is declared on the role of the referenced entity B — the role that entity plays in the fact (Halpin ORM convention). The FK column itself lives in entity A’s table; its name is derived from the role that B plays here.

Role names are necessary in three situations:

  1. Renamed foreign keys. The child table uses a different column name than the parent's primary key. Example: EventLog.ActorId references Identity.IdentityId.
  2. Multiple references to the same entity. A single table references the same parent more than once. Example: Flight has both DepartureAirportCode and ArrivalAirportCode, both referencing Airport.AirportCode.
  3. Self-referential relationships. An entity references itself through a distinctly named column. Example: Project.ParentProjectId references Project.ProjectId.

When the referenced entity’s reference scheme is composite (Section 2.4), the roleName, where declared, is a comma-delimited string of column names aligned position-by-position with the reference scheme. A join over such a relation must equate every aligned column pair.

2.10 Derived Value Types

A Derived Value Type is a value type whose value is not stored as a physical database column but is instead computed from a row-level formula over other value types. Let v_d \in \mathcal{V} be a derived value type. Its value for any tuple is defined by a formula \varphi over sibling and related value types:

$$v_d = \varphi(v_1, v_2, \ldots, v_k) \quad \text{where each } v_i \in \mathcal{V}$$

A derived value type is declared by setting isDerived: true and providing a formula string on the entity. The formula is an arithmetic or functional expression that references other value types by name:

  • Local references: Plain names refer to value types on the same parent entity. Example: a derived value type Profit on entity Order with formula Revenue - COGS references the Revenue and COGS columns on the Order table.
  • Related references (dot notation): Names in the form Entity.Column refer to a value type on a related entity, traversing a relationship defined in the graph. Example: a derived value type LineTotal on entity OrderDetail with formula Quantity * Product.UnitPrice resolves Product.UnitPrice by following the fact type that connects OrderDetail to Product. Where an entity name is ambiguous across namespaces (Section 2.1), the related reference must qualify it: namespace.Entity.Column.

When an LLM generates SQL for a query involving a derived value type, it must expand the formula inline as a SQL expression rather than referencing a column name. Related references require a JOIN to the referenced entity’s table. A derived value type name must never appear as a raw column in WHERE, GROUP BY, or HAVING clauses; the expanded expression (or a wrapping subquery/CTE) must be used instead.

Derived value types carry a valueDataType like any other value type, indicating the expected result type of the formula (e.g., Currency for a monetary computation). They participate in fact types, constraints, and all other GRAM constructs identically to physical value types.

2.11 Aliases

An Alias is an optional human-readable name for an entity type or value type whose physical name is not semantically meaningful. Legacy and enterprise databases frequently use cryptic identifiers (e.g., T_EMP_01 for a table, OM1R06 for a column) that carry no semantic signal for an LLM or a human user. An alias bridges this gap without altering the physical schema.

Formally, for any e \in (\mathcal{E} \cup \mathcal{V}), an optional alias \alpha(e) provides an alternative identifier:

\alpha: (\mathcal{E} \cup \mathcal{V}) \rightharpoonup \text{String}

where \rightharpoonup denotes a partial function (the alias is not required). When \alpha(e) is defined, it becomes the primary identifier for LLM reasoning, question matching, and fact type display. The physical name remains the exclusive target for SQL generation—table names in FROM and JOIN clauses, column names in SELECT, WHERE, GROUP BY, and ORDER BY clauses.

An alias is declared by setting the alias property on an entity or value type:

{
  "name": "T_EMP_01",
  "alias": "Employee",
  "referenceScheme": "EMP_ID",
  "isValueType": false
}
{
  "name": "OM1R06",
  "alias": "FirstName",
  "isValueType": true,
  "valueDataType": "Text"
}

Both the alias and the physical name are valid references in user questions. An LLM that encounters the alias Employee in a question matches it to the entity whose alias is Employee, then uses the physical name (T_EMP_01) in the generated SQL. If no alias is present, the physical name serves both purposes—this is the default for well-named schemas where column names already carry semantic meaning.

One alias per entity or value type. Multiple aliases are not supported; alternate readings on fact types already provide synonym coverage for relationship-level matching. Aliases do not affect structural constraints, cardinality, or join logic—they are purely a semantic labeling mechanism. Roles carry their own alias property, defined in Section 2.12.

2.12 Role Aliases

A Role Alias is an optional human-readable label for a role whose physical roleName is not semantically meaningful. It extends the alias mechanism of Section 2.11 one level down, restoring a distinction present in Halpin’s ORM but collapsed in GRAM v1.0: the conceptual role name—the part an entity plays in a fact, always a noun phrase (“authorizer,” “departure airport”)—versus the physical column name that implements it.

A role alias is declared as alias on a role, alongside roleName:

{
  "entityName": "Employee",
  "roleName": "OM2R11",
  "alias": "AuthorizedBy",
  "isUnique": false,
  "isMandatory": false
}

The same discipline as entity aliases applies: the alias is the identifier for LLM reasoning, question matching, and display; the physical roleName is the exclusive target for SQL generation. A role alias is the designated lexical carrier (Section 3.3) for multi-path relationships whose physical foreign key names carry no semantic signal—the case in which neither the role name nor a generic predicate can disambiguate user intent. One alias per role; for composite role names (Section 2.9) a single alias labels the role as a whole.

3. The Predicate Calculus of GRAM

3.1 Atomic Predicates

When a user defines a fact in a GRAM graph, they define the membership criteria for a relation. Each fact's reading property constitutes an atomic predicate. For a binary fact type between entities E_1 and E_2:

$$P(x, y) \quad \text{where } x \in E_1, \; y \in E_2$$
GRAM Property Formal Definition Significance
readingAtomic Predicate P(x, y)Defines the semantic truth of the relation
entityNameDomain E_i \in (\mathcal{E} \cup \mathcal{V})Restricts each role to a declared entity or value type
isUniqueFunctional Dependency X \to YDefines cardinality and uniqueness
isMandatoryExistence Constraint \forall x\, \exists yDefines total participation

3.2 Inverse Readings

For each binary Fact Type, the GRAM specification explicitly captures the Inverse Reading, ensuring that the relation is not a directed pointer (as in a Foreign Key) but a bi-directional logical assertion. If the forward reading is "Employee handles Order", the inverse is "Order is handled by Employee". This duality enables an LLM to traverse the graph in either direction without ambiguity.

3.3 Predicate Specificity and Disambiguation

A machine consumer performs two distinct disambiguation jobs when translating a question into SQL: determining how to join (join type, direction, cardinality, aggregation shape) and determining which relationship the question refers to. The first job is fully determined by constraint modality (Section 4) and reference metadata; it never requires lexical content. The second job arises only when the same entity pair participates in more than one fact type.

For single-path relationships—where exactly one fact type connects a given entity pair—no lexical requirement exists at all. “Customer has Order” and “Customer places Order” produce identical SQL because the structural metadata (entities, roles, constraints, reference schemes) fully determines the query. The choice of verb is a readability concern for human modelers.

For multi-path relationships—where two or more fact types connect the same entity pair—the structural side is already disambiguated by role names: two foreign key columns in one table cannot share a name, so distinct roleName values always exist (Section 2.9). The intent side, however, is information-theoretic: if two fact types with identical constraint patterns carry no lexical difference anywhere, no consumer of any capability can map “who authorized this order?” to the correct relation—there is no signal to read. The requirement is therefore disjunctive: each fact type in a multi-path pair must carry lexical signal in at least one of three carriers—the role name, a role alias (Section 2.12), or a distinct predicate verb.

Empirical evaluation (Kench, 2026) shows that when role names carry the signal (e.g., SubmittedById, DepartureAirportCode—the common case, since the humans who named those columns needed to distinguish them too), substituting a generic verb for every predicate produces no measurable text-to-SQL accuracy loss: the verb is a redundant carrier. Role names are typically nominalized verbs (“AuthorizedBy,” “handler”), and the lexical stem survives the change of grammatical form. The verb becomes load-bearing only where the physical column names are cryptic and no role alias is declared—and, potentially, in domains whose specialized terminology is weakly represented in a model’s training corpus, where descriptive predicates may carry signal that structural metadata cannot replace.

Formal criterion. Predicate specificity is a conformance concern when and only when an entity pair participates in more than one fact type. Single-path relationships carry no lexical requirement; generic verbs (e.g., “has”, “is associated with”) are fully conformant. Each fact type in a multi-path pair must carry lexical signal in at least one carrier (role name, role alias, or distinct predicate verb). Distinct, semantically meaningful predicates are recommended for all fact types as the pedagogical surface (Section 3.4), but are not an operational requirement where another carrier holds the signal.

3.4 Operational and Pedagogical Semantics

A GRAM schema is consumed at two layers, and v1.1 formalizes the distinction (Kench, 2026).

The machine layer consumes the constraint modality—uniqueness, mandatoriness, and the cardinality classification they jointly determine (Section 4)—together with role-level identifiers (role names, role aliases) and reference metadata. This content determines every operational property of a generated query: join type, join columns, direction, grouping, and aggregation. Empirically, it is sufficient: a model consuming a schema in which every predicate verb has been replaced by a generic label generates SQL at accuracy indistinguishable from a schema with descriptive verbs, provided constraints and role names are intact.

The human layer consumes the natural-language readings. Verbalization is the medium through which domain experts author, validate, and correct the model without competence in formal logic—a fact type that can be read as a natural sentence is checkable by the person who knows whether it is true. This layer is not decorative: it is the working surface of conceptual-stage modeling (Section 8.1) and the reason a GRAM schema can be reviewed by the business it describes.

The role is the junction where the two layers meet: a role name is simultaneously lexical content (a nominalized verb carrying intent-matching signal) and structural content (the physical column emitted in SQL). It is the one property with a foot in each layer, and the reason predicate verbalization can be demoted to the human layer without operational loss (Section 3.3).

The two layers correspond to the two conformance classes of Section 8: GRAM-Conceptual is complete at the human layer; GRAM-Physical adds the bindings the machine layer requires.

4. Constraint Formalization

Constraints in the GRAM specification are not auxiliary metadata; they are first-class logical laws governing the behavior of each relation.

4.1 Uniqueness Constraints and Functional Dependencies

The isUnique property on a role defines a constraint on the relation. If role r_1 is unique in a binary relation between E_1 and E_2, we have a function f: E_1 \rightarrow E_2:

$$\forall x \in E_1,\; \forall y, z \in E_2 : \bigl(P(x, y) \land P(x, z)\bigr) \implies y = z$$

This is not a database configuration option; it is a logical law. When an LLM interprets a GRAM-compliant graph, it does not guess join cardinality. It computes the deterministic path of the query. By capturing uniqueness at the role level, the specification explicitly identifies the candidate keys of every relation.

4.2 Mandatoriness and Existence Constraints

The isMandatory property defines an existence dependency. If entity E_1 must participate in predicate P:

$$\forall x \in E_1\; \exists y \in E_2 : P(x, y)$$

An LLM receiving this constraint knows to generate an INNER JOIN. Without it, the appropriate operation is a LEFT JOIN. This distinction is the difference between a correct result set and a missing-row error.

4.3 Cardinality Classification

The combination of uniqueness constraints on roles in a binary fact type determines the cardinality of the underlying relation:

Role 1 Unique Role 2 Unique Cardinality Interpretation
NoNoN{:}MMany-to-many; relation is irreducible
YesNo1{:}NFunctional dependency; one side determines the other
NoYesN{:}1Functional dependency (reverse direction)
YesYes1{:}1Bijection; both sides determine each other

5. The Ontological Failure of SQL DDL

Conventional metadata management suffers from an ontological collapse. By treating DDL as a sufficient semantic source, practitioners commit a category error. DDL defines the physical schema (the mechanism of storage) but remains silent on the conceptual schema (the nature of the facts being stored).

This distinction is not new. Codd (1970) argued for separating data representation from storage; Chen (1976) formalized it with the Entity-Relationship model; Halpin (1989–2006) advanced it with Object-Role Modeling, grounding conceptual schemas in natural-language predicates. Yet the gap persists—a FOREIGN KEY constraint in SQL enforces referential integrity but does not express the predicate. Consider:

ALTER TABLE Orders
    ADD CONSTRAINT FK_Emp
    FOREIGN KEY (EmpID) REFERENCES Employees(ID);

This statement tells the database engine "do not break the link." It provides no information about what the link means: whether an employee handles, approves, or delivers the order. The GRAM specification resolves this by binding every relation to an explicit natural-language predicate.

6. Normative Comparison

The following comparison illustrates the difference between physical metadata and a GRAM-compliant semantic representation for the query: "How many orders were handled by each employee?"

6.1 DDL-Only Interpretation

An LLM operating on DDL alone observes a nullable EmpID column in the Orders table. It must infer join semantics, potentially selecting a LEFT JOIN when an INNER JOIN is correct, miscounting null entries, or double-counting in misidentified many-to-many relationships.

6.2 GRAM-Compliant Interpretation

An LLM receiving the GRAM graph reads:

"Employee handles Order. Each Order must be handled by exactly one Employee."

The mandatoriness constraint (\forall Order \exists Employee) dictates an INNER JOIN. The uniqueness constraint on the Order role establishes the functional dependency \text{Order} \to \text{Employee}, confirming a 1{:}N cardinality. The generated query is deterministic:

SELECT e.EmployeeName, COUNT(o.OrderID) AS OrderCount
FROM Employees e
INNER JOIN Orders o ON o.EmpID = e.ID
GROUP BY e.EmployeeName;

7. Schema Representation

A GRAM-compliant schema is serialized as a JSON document. The document envelope declares the specification version (gramVersion) and the maturity stage (stage; Section 8.1). The following fragment illustrates a representative subset of a physical-stage schema, exercising every normative feature: entities with reference schemes and sample values, a composite reference scheme, an optional namespace for database schema qualification (applicable only to non-value-type entities), aliases for cryptic physical names, a role alias over a cryptic foreign key, value types spanning all seven data types, a value type enum, an entity enum, a self-referential relationship with a role name, multiple references to the same entity, an alternate reading, and varied constraint patterns.

{
  "gramVersion": "1.1",
  "stage": "physical",
  "entities": [
    {
      "name": "Employee",
      "namespace": "dbo",
      "referenceScheme": "empId",
      "isValueType": false,
      "isEnum": false,
      "sampleValues": ["Alice Chen", "Bob Martinez"]
    },
    {
      "name": "Order",
      "referenceScheme": "orderId",
      "isValueType": false,
      "isEnum": false,
      "sampleValues": ["ORD-1001", "ORD-1002"]
    },
    {
      "name": "OrderDetail",
      "referenceScheme": "orderId,productId",
      "isValueType": false,
      "isEnum": false
    },
    {
      "name": "Project",
      "referenceScheme": "projectId",
      "isValueType": false,
      "isEnum": false,
      "sampleValues": ["Apollo", "Horizon"]
    },
    {
      "name": "T_DEPT_01",
      "alias": "Department",
      "referenceScheme": "code",
      "isValueType": false,
      "isEnum": true,
      "enumValues": ["Engineering", "Marketing", "Sales", "HR"]
    },
    {
      "name": "OM1R06",
      "alias": "FirstName",
      "isValueType": true,
      "valueDataType": "Text"
    },
    {
      "name": "OrderDate",
      "isValueType": true,
      "valueDataType": "Date"
    },
    {
      "name": "OrderTotal",
      "isValueType": true,
      "valueDataType": "Currency"
    },
    {
      "name": "HeadCount",
      "isValueType": true,
      "valueDataType": "Number"
    },
    {
      "name": "IsActive",
      "isValueType": true,
      "valueDataType": "Boolean"
    },
    {
      "name": "Quantity",
      "isValueType": true,
      "valueDataType": "Integer"
    },
    {
      "name": "ShippedAt",
      "isValueType": true,
      "valueDataType": "DateTime"
    },
    {
      "name": "OrderStatus",
      "isValueType": true,
      "valueDataType": "Text",
      "isEnum": true,
      "enumValues": ["Pending", "Shipped", "Delivered", "Cancelled"]
    },
    {
      "name": "LineTotal",
      "isValueType": true,
      "valueDataType": "Currency",
      "isDerived": true,
      "formula": "Quantity * Product.UnitPrice"
    }
  ],
  "factTypes": [
    {
      "reading": "Employee handles Order",
      "inverseReading": "Order is handled by Employee",
      "alternateReadings": ["Employee processes Order"],
      "arity": 2,
      "roles": [
        { "entityName": "Employee", "isUnique": false, "isMandatory": false },
        { "entityName": "Order", "isUnique": true, "isMandatory": true }
      ]
    },
    {
      "reading": "Employee submits Order",
      "inverseReading": "Order is submitted by Employee",
      "arity": 2,
      "roles": [
        { "entityName": "Employee", "roleName": "SubmittedById", "isUnique": false, "isMandatory": false },
        { "entityName": "Order", "isUnique": true, "isMandatory": true }
      ]
    },
    {
      "reading": "Employee authorizes Order",
      "inverseReading": "Order is authorized by Employee",
      "arity": 2,
      "roles": [
        { "entityName": "Employee", "roleName": "OM2R11", "alias": "AuthorizedBy", "isUnique": false, "isMandatory": false },
        { "entityName": "Order", "isUnique": true, "isMandatory": false }
      ]
    },
    {
      "reading": "Employee has FirstName",
      "inverseReading": "FirstName is of Employee",
      "arity": 2,
      "roles": [
        { "entityName": "Employee", "isUnique": true, "isMandatory": true },
        { "entityName": "OM1R06", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Employee has IsActive",
      "inverseReading": "IsActive is of Employee",
      "arity": 2,
      "roles": [
        { "entityName": "Employee", "isUnique": true, "isMandatory": true },
        { "entityName": "IsActive", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Employee works for Department",
      "inverseReading": "Department employs Employee",
      "arity": 2,
      "roles": [
        { "entityName": "Employee", "isUnique": false, "isMandatory": true },
        { "entityName": "T_DEPT_01", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Order has OrderDate",
      "inverseReading": "OrderDate is of Order",
      "arity": 2,
      "roles": [
        { "entityName": "Order", "isUnique": true, "isMandatory": true },
        { "entityName": "OrderDate", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Order has OrderTotal",
      "inverseReading": "OrderTotal is of Order",
      "arity": 2,
      "roles": [
        { "entityName": "Order", "isUnique": true, "isMandatory": true },
        { "entityName": "OrderTotal", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Order has OrderStatus",
      "inverseReading": "OrderStatus is of Order",
      "arity": 2,
      "roles": [
        { "entityName": "Order", "isUnique": true, "isMandatory": true },
        { "entityName": "OrderStatus", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "OrderDetail has Quantity",
      "inverseReading": "Quantity is of OrderDetail",
      "arity": 2,
      "roles": [
        { "entityName": "OrderDetail", "isUnique": true, "isMandatory": true },
        { "entityName": "Quantity", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Order has ShippedAt",
      "inverseReading": "ShippedAt is of Order",
      "arity": 2,
      "roles": [
        { "entityName": "Order", "isUnique": true, "isMandatory": false },
        { "entityName": "ShippedAt", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Department has HeadCount",
      "inverseReading": "HeadCount is of Department",
      "arity": 2,
      "roles": [
        { "entityName": "T_DEPT_01", "isUnique": true, "isMandatory": false },
        { "entityName": "HeadCount", "isUnique": false, "isMandatory": false }
      ]
    },
    {
      "reading": "Project is sub-project of Project",
      "inverseReading": "Project has sub-project Project",
      "arity": 2,
      "roles": [
        { "entityName": "Project", "isUnique": false, "isMandatory": false },
        { "entityName": "Project", "roleName": "ParentProjectId", "isUnique": false, "isMandatory": false }
      ]
    }
  ]
}

In this representation:

  • Envelope. gramVersion identifies the specification version the document conforms to; stage declares its conformance class (Section 8.1).
  • Reference schemes. The referenceScheme on Employee ("empId"), Order ("orderId"), and Project ("projectId") identifies the join key column for each entity. OrderDetail declares a composite reference scheme ("orderId,productId"); joins against it must equate both column pairs, and any referencing roleName would be a matching comma-delimited string (Sections 2.4, 2.9).
  • Namespace. The optional namespace on Employee ("dbo") specifies the database schema that qualifies the table name (e.g., dbo.Employee). When present, the fully-qualified name is namespace.name. This field is only applicable to non-value-type entities; value types inherit context from their owning entity. Entities with different namespaces but the same name (e.g., Sales.Customer and Finance.Customer) are treated as distinct.
  • Functional dependency. The uniqueness of the Order role in “Employee handles Order” establishes \text{Order} \to \text{Employee} (each order is handled by exactly one employee).
  • Total participation. The mandatoriness of the Order role asserts \forall Order, \exists Employee, dictating an INNER JOIN.
  • Alternate readings. The alternateReadings array on “Employee handles Order” provides synonymous phrasings (“Employee processes Order”) for question-to-relation matching.
  • Aliases. Department is declared with the physical name T_DEPT_01 and an alias of "Department". The LLM uses the alias for reasoning and display, but emits T_DEPT_01 in SQL. Similarly, the value type OM1R06 carries an alias of "FirstName". Both the alias and physical name are valid in user questions.
  • Role alias. The Employee role in “Employee authorizes Order” carries the physical roleName "OM2R11" with the alias "AuthorizedBy". The alias is the reasoning and matching identifier; OM2R11 is emitted in SQL (Section 2.12).
  • All seven data types. Value types demonstrate every normative data type: Text (FirstName / OM1R06), Number (HeadCount), Integer (Quantity), Date (OrderDate), DateTime (ShippedAt), Currency (OrderTotal), and Boolean (IsActive). Each type directs the LLM to the appropriate SQL functions and aggregation strategies; the Integer/Number and Date/DateTime distinctions prevent the silent integer-division and day-boundary errors described in Section 2.5.
  • Value type enum. OrderStatus declares enumValues with a valueDataType of Text, giving the LLM a closed set of valid filter values for status queries.
  • Entity enum. Department (physical name T_DEPT_01) declares enumValues as a first-class entity referenced by other facts, enabling precise WHERE ... IN (...) clauses and exhaustive groupings.
  • Sample values. Concrete instances on Employee, Order, and Project disambiguate what each entity represents and provide realistic test data.
  • Self-referential relationship. “Project is sub-project of Project” references the same entity in both roles. The roleName of "ParentProjectId" disambiguates the FK column, which would otherwise collide with the entity’s own projectId.
  • Multi-path disambiguation. “Employee submits Order” and “Employee authorizes Order” create second and third FKs from Order to Employee. The roleName values ("SubmittedById", "OM2R11") disambiguate the physical join columns. Lexical signal for intent matching travels in the carriers required by Section 3.3: SubmittedById carries its own signal as a nominalized verb; the cryptic OM2R11 carries none, so its role declares the alias "AuthorizedBy". The distinct verbs “handles,” “submits,” and “authorizes” serve the human layer and provide redundant signal for the machine layer.
  • Derived value type. LineTotal declares isDerived: true with a formula of "Quantity * Product.UnitPrice". This is not a physical column; an LLM must expand it inline (e.g., od.Quantity * p.UnitPrice AS LineTotal) and JOIN to the Product table to resolve the related reference.
  • Attribute-fact constraint convention. For entity-to-value-type facts, uniqueness and mandatoriness are declared on the owning entity’s role: “Order has OrderDate” carries isUnique: true, isMandatory: true on the Order role — each Order has exactly one OrderDate (a NOT NULL column). Per Section 4.1, the unique role’s player determines the other side; placing uniqueness on the value-type role would assert the converse (no two orders share a date). Optional attributes (ShippedAt, HeadCount) keep the entity role’s uniqueness and drop its mandatoriness — a nullable column.
  • Varied constraint patterns. The example includes mandatory attributes (FirstName, OrderDate, OrderTotal, OrderStatus), optional attributes (ShippedAt, HeadCount), a mandatory-one-side entity relationship (Employee works for Department), and a fully optional self-referential relationship (Project sub-project), illustrating how constraint metadata governs JOIN type and NULL handling.

A conceptual-stage document declares "stage": "conceptual" and is complete without any physical binding—no reference schemes, data types, namespaces, or role names are required (Section 8.1). This is the serialization of a schema captured during elicitation, before (or independent of) a database:

{
  "gramVersion": "1.1",
  "stage": "conceptual",
  "entities": [
    { "name": "Customer", "isValueType": false },
    { "name": "Complaint", "isValueType": false }
  ],
  "factTypes": [
    {
      "reading": "Customer raises Complaint",
      "inverseReading": "Complaint is raised by Customer",
      "arity": 2,
      "roles": [
        { "entityName": "Customer", "isUnique": false, "isMandatory": false },
        { "entityName": "Complaint", "isUnique": true, "isMandatory": true }
      ]
    }
  ]
}

8. Conformance

The JSON structure defined in Section 7 constitutes the normative serialization format of the GRAM specification. Any system that produces or consumes schemas in this format is subject to the conformance requirements below.

Version 1.1 defines two conformance classes, corresponding to the two consumption layers of Section 3.4 and the two stages of a schema’s life cycle. A document declares its class in the envelope via the stage property ("conceptual" or "physical").

8.1 Conformance Classes

GRAM-Conceptual is the class of schemas that capture a domain’s business grammar independent of any physical database: entities, fact types with natural-language readings, and constraint declarations. It is the artifact of conceptual-stage modeling—elicitation, domain-expert validation, and design—and is complete at the human layer. A conceptual document is a first-class, conformant GRAM artifact, not an incomplete physical one. It is not sufficient for SQL generation.

GRAM-Physical extends GRAM-Conceptual with the physical bindings the machine layer requires: reference schemes, data types, role names, and namespace qualification. A physical document is sufficient for deterministic machine consumption, including text-to-SQL generation.

A physical-stage document must satisfy the requirements of both classes.

8.2 Requirements

A system is GRAM-Conceptual conformant if it satisfies the following requirements:

  1. Every relation in the schema is expressed as a Fact Type with an explicit natural-language reading.
  2. Binary Fact Types include both the forward reading and the inverse reading.
  3. Each role carries explicit isUnique and isMandatory constraint declarations.
  4. Role order is normative: the roles array binds roles to reading positions (Section 2.3) and must not be reordered.
  5. The document envelope declares gramVersion and stage.
  6. Where enumerated types are declared, the complete set of allowed values is exported as enumValues.
  7. The serialization format preserves the predicate structure, semantic enrichment (alternate readings, sample values), and is machine-parseable (JSON).

A system is GRAM-Physical conformant if it additionally satisfies:

  1. Each entity type declares a referenceScheme identifying its preferred key—a single column name, or a comma-delimited string of column names for composite keys (Section 2.4).
  2. Value types declare a valueDataType from the normative set (Text, Number, Integer, Date, DateTime, Boolean, Currency).
  3. Roles that produce foreign key columns with names differing from the referenced entity’s reference scheme declare an explicit roleName; where the reference scheme is composite, the role name is a comma-delimited string aligned with it (Section 2.9).
  4. Derived value types declare isDerived: true and a formula string expression that references other value types by name (local) or by dot notation (related).
  5. When an entity, value type, or role carries an alias, the alias is used for LLM reasoning and user-facing display; the physical name (or roleName) is used exclusively for SQL generation. Both are accepted as valid identifiers in user queries.
  6. Role entityName values and derived-formula references use the fully-qualified namespace.name form wherever the bare name is ambiguous across namespaces (Section 2.3).
  7. Each fact type in a multi-path entity pair carries lexical signal in at least one carrier: role name, role alias, or distinct predicate verb (Section 3.3).

Conformant implementations ensure that any automated system consuming a physical-stage schema can determine the correct join semantics, cardinality, and participation constraints for every relation—replacing structural inference with a declared business grammar that is the single source of truth for text-to-SQL generation.

9. Future Work

The following capabilities are deliberate deferrals from v1.1—omissions by decision, not oversight. Each has real significance for machine reasoning; each is excluded because its machinery exceeds the scope of a point release.

  • Subtyping. Entity inheritance (e.g., Employee IS-A Person), as realized physically in shared-key one-to-one tables, discriminator columns, and table-per-class patterns. The machine-consumable content is the applicability rule: which facts apply to which subtype, and which discriminator filters are mandatory before subtype-specific columns are touched.
  • External uniqueness constraints. Uniqueness spanning roles of different fact types (e.g., an order number unique within its customer), which per-role isUnique cannot express.
  • Ring constraints. Declared logical properties of self-referential fact types—acyclicity, irreflexivity—that formally license recursive traversal (e.g., recursive CTEs over an organizational hierarchy).
  • Value-range constraints. Bounded numeric and date domains beyond enumeration (e.g., Quantity > 0).
  • Provenance. Distinguishing constraints verified against a source schema from constraints asserted by documents or domain experts. Deferred until the consumer treatment of asserted constraints is settled; an asserted mandatoriness that proves false reintroduces the silent missing-row error the specification exists to eliminate.

References

  1. Codd, E. F. (1970). "A Relational Model of Data for Large Shared Data Banks." Communications of the ACM, 13(6), 377–387.
  2. Halpin, T. (2006). Information Modeling and Relational Databases. 2nd ed. Morgan Kaufmann.
  3. Date, C. J. (2003). An Introduction to Database Systems. 8th ed. Addison-Wesley.
  4. Chen, P. P. (1976). "The Entity-Relationship Model: Toward a Unified View of Data." ACM Transactions on Database Systems, 1(1), 9–36.
  5. Kench, E. (2026). "The Lexical Independence of Schema Semantics: Constraint Modality, Not Predicate Verbalization, Determines LLM Text-to-SQL Accuracy." Independent Research.

Cite This Work

Kench, E. (2026). Ormle: A Predicate-Based Knowledge Graph Representation for Deterministic Text-to-SQL Reasoning. Technical Specification v1.0. Zenodo. https://doi.org/10.5281/zenodo.19037879

BibTeX

@techreport{kench2026ormle,
  author      = {Kench, Edward},
  title       = {Ormle: A Predicate-Based Knowledge Graph
                 Representation for Deterministic
                 Text-to-SQL Reasoning},
  institution = {Independent Researcher},
  year        = {2026},
  month       = {March},
  type        = {Technical Specification},
  doi         = {10.5281/zenodo.19037879},
  url         = {https://gramspec.com/GRAM}
}