Prefix: intent_.

The derivation layer: what follows once the schema’s readings, the database catalog and the classpath census are put side by side. Rows here are computed, never captured; each view states one rule, and taller derivations are built by reading shorter ones. This is the family the generator and the editor tooling actually plan from.

Where to start

intent_spelled_table

How a written table name resolves against the catalog census: one row per candidate table, keyed on the spelling itself rather than on any one site that wrote it.

intent_bound_table

Which catalog table an @table-bearing type is bound to: graphitron_table’s reference resolved through intent_spelled_table, one row per candidate table.

intent_resolved_field_claim

The field-grain claim resolution: the authored relation unioned with the inferred rows at coordinates the authored relation does not cover.

intent_node_type

Which of a graph’s types are node types: the union of the authored @node population and the inferred one.

How this family meets the others

Declared key edges
store_

24 foreign keys from this family’s rows into that one.

graphql_

4 foreign keys from this family’s rows into that one.

Why the name is right

The third and topmost layer of the SDL depth ordering, graphql_ under graphitron_ under this name, whose upper two layers are both derivation over what graphql_ captured: what gets derived once something resolves and combines those readings into what the generator will actually do. The residents are views plus the materialized derivations, and a materialized one owns why it is stored in one of two places: its own table comment where no view could express the rule, or its meta_materialize row where a view expresses the rule correctly and only too slowly. That changes nothing about the name, since a family is named for whose vocabulary its rows are written in and materialization is not the discriminator. A registered reduction is two relations under one rule, the _live view stating it and the canonically named table holding it, and both are residents here for the same reason. The stratum has two layers, and a new resident picks one deliberately: the base derivations (the authored claim views, one per grain; the structural classifier views, one per classifier so each carries exactly its own witness columns; the resolutions those classifiers stand on, which earn their own relation as soon as a second reader asks them and which layer among themselves on that same rule, a resolution keyed on a written name sitting under the ones keyed on a coordinate; the demand and exemption rule views, stated at the grain their rules are authored at), and the reductions over them (intent_resolved_field_claim and the resolved demand views, the resolution expressions a planning reader joins). No relation should acquire the prefix by drifting into it; each new derived resident is its own change.

intent_argmapping_binding_leaf (view)

The last thing an argMapping path bound, and whether that thing carries a @nodeId. A reduction over intent_argmapping_segment_binding and not a resolution of its own, which is what the leaf reading costs: the leaf is the bound segment with no bound successor, and this view exists so that the readers needing it (the key projection beside it, and the detections that reject a bare or unresolvable spelling) share one spelling of "no bound successor" rather than one each. Prefix-density upstream is what makes the definition sound: the bound positions of a pair are 0 through some k with no hole, so "no successor" identifies exactly one row per pair and the arity is one answer rather than a set. Absence means the path bound nothing at all, which at a path-step @condition is every path (the walk resolves there against an empty slot map) and at every other site is a head naming no slot the site has in scope. Both are rejections the walk already returns from ArgBindingMap.of before the store is written, so neither is this relation’s to restate; the row is absent here because there is no leaf, not because the fact is unavailable, and a reader wanting it joins intent_argmapping_pair against this relation to find the pairs with no leaf. The @nodeId reading is two columns and not a verdict, because three answers are wanted and a fork would collapse two of them: no directive at all is the ordinary binding, a directive with typeName: is the projectable case, and a directive without one is the bare spelling that cannot infer a node type at this position, there being no containing table to infer it from. Which of the two @nodeId relations answers follows from bound_kind, so an argument binding and an input-field binding are one row shape rather than two readings.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the binding relation

site (CHARACTER VARYING, nullable)

which SDL site spelled the pair, in intent_argmapping_pair’s closed vocabulary of eight; with the use-site key and the position this is the grain, and it is what a consumer switches on to know whether an emitter is wired for the answer

use_site (CHARACTER VARYING, nullable)

the consuming coordinate, serialized as intent_argmapping_pair serializes it; the coordinate a rejection about this pair names, and the key a reader joins that relation on to recover the arm’s own components

type_name (CHARACTER VARYING, nullable)

the spelling site’s owning type, carried so the segment decomposition is one join away

field_name (CHARACTER VARYING, nullable)

the spelling site’s field name within that type

position (INTEGER, nullable)

the pair’s 0-based position within its own argMapping list

argument_path (CHARACTER VARYING, nullable)

the path as written, carried so a message can quote what the author wrote and so the segment rows are reachable without a second read of the pair

segment_position (INTEGER, nullable)

where the path stopped: the 0-based position of the last segment that bound. 0 means only the head bound, which on a single-segment path is the whole path and on a dotted one is a name below the head that resolved to nothing. The position a reader adds one to in order to name the first segment that bound nothing

bound_kind (CHARACTER VARYING, nullable)

ARGUMENT where the leaf is a field argument, INPUT_FIELD where it is an input field; carried from the binding relation, and what tells an emitter which slot the wire value is read out of

bound_type_name (CHARACTER VARYING, nullable)

the leaf’s owning type, carried from the binding relation

bound_field_name (CHARACTER VARYING, nullable)

the leaf’s owning field on an ARGUMENT leaf, the input field itself on an INPUT_FIELD leaf

bound_argument_name (CHARACTER VARYING, nullable)

the argument’s name on an ARGUMENT leaf; NULL on an INPUT_FIELD leaf, whose key needs no argument component

node_id_declared (BOOLEAN, nullable)

whether the leaf carries a @nodeId at all. FALSE is the ordinary binding, where the wire value is the value and no decode is implied; TRUE says a decode is, and the column beside it says whether the author named what to decode against. Kept as its own column rather than read off a NULL node type, because the two NULLs mean opposite things and a reader collapsing them would treat the bare spelling as an ordinary binding, which is the silence the projection exists to close

node_type_ref (CHARACTER VARYING, nullable)

the typeName: the leaf’s @nodeId names, as written; NULL where the directive is absent, and NULL where it is present without one, which at this position is a rejection rather than an inference, there being no containing table to infer a node type from. Read with node_id_declared, never alone

trailing_segments (INTEGER, nullable)

how many segments the path spells beyond the leaf: 0 where the path bound everything it spelled, 1 where one name is left over, more where several are. A count rather than a flag, because the readings differ: zero on a @nodeId leaf is the bare binding a rejection closes, one is a key-column projection, and two or more is a typo or a nested form neither this relation nor its readers claim to resolve. Counted over the segment rows above the leaf’s position rather than derived from a path length, so it is arithmetic over rows and never a parse

leaf_named_type (CHARACTER VARYING, nullable)

the leaf’s own SDL named type, wrappers stripped, coalesced from whichever of graphql_argument and graphql_field the bound kind points at. What a message needs in order to say what the author tried to open: an ID that declares no @nodeId is told to annotate it, while a String is told it has nothing to open at all, and those are two remedies for one shape. Never NULL, both base relations declaring it NOT NULL and the bound coordinate always naming a row in one of them

leaf_is_list (BOOLEAN, nullable)

whether the leaf’s SDL type carries a list wrapper, coalesced the same way. Read where the leaf is a node id with one trailing segment: a list of node ids names the list of that key column across the decoded ids, which is a coherent request and not an author mistake, so nothing here rejects it and the consumer that knows which emitters exist defers on it. Carried on the leaf rather than re-joined by each reader, because the coalesce over the two coordinates is the same one the @nodeId columns beside it already perform and two spellings of it would be two chances to disagree about which relation answers

intent_argmapping_bound_parameter_type (view)

The Java type the left side of an argMapping pair denotes: what the value the path resolves has to be assignable to. The missing half of every type question about this family, and the reason one existed to be missing is that the two populations answering it are unrelated relations. A @routine parameter is a position on a generated Routines method and its type comes from the catalog census, while every other site’s parameter is a position on an authored Java method and its type comes from the classpath census; a reader wanting "the type of the parameter this pair binds" had to know which of the two to ask, and therefore had to switch on site, which is the switch this relation performs once. One row per pair whose parameter resolves, at intent_argmapping_pair’s own grain, so it joins that relation and everything derived from it on site, use_site and position with no reshaping. Eight arms over that vocabulary, and the split is not the pair view’s: seven of them resolve an authored (class, method) pair the same way and differ only in which owner relation carries it, which is why they share one CTE and one join onto the classpath census; the routine arm is the eighth and reaches sql_routine_parameter through intent_field_routine_method instead. Matching is by parameter name on both sides, which is the same match the generator itself makes and inherits the same dependency: a consumer compiling without -parameters has no names to match, so a pair resolves nothing here and every reader sees that as absence. One vocabulary on both arms, and reaching it is the reason the classpath arm joins one relation further than it looks like it needs to. The catalog arm’s binding type is fully qualified, while jvm_method_parameter.parameter_type drops the package by design; comparing the two would never match, and the mismatch would look exactly like a genuine type disagreement. So the classpath arm takes the root of the parameter’s declared-type decomposition instead, jvm_method_parameter_type_ref at the empty type_path, whose referenced_class is the qualified binary name. That relation has no row where the position names no class, so a primitive parameter resolves nothing here rather than resolving int: honest, and worth stating, since an author binding a key column to an int parameter gets the gate standing aside rather than a rejection. Absence is therefore four facts and this relation distinguishes none of them: the reference resolved no method, the method declares no parameter of that name, names were not compiled in, or the parameter’s type names no class. That is deliberate, each being a condition other relations already state or reject, and it is what keeps this relation one answer rather than a verdict; what a reader does where the answer is missing is the reader’s own decision, and the projection’s own comment argues its choice. What it must not do is decide the reading, which is why candidates is a column: an overloaded method or a class declared by two classpath entries resolves two rows, and a reader requiring one type requires candidates = 1 rather than picking. DISTINCT within each arm collapses the ordinary duplicate, one method reached through two graph sources naming the same type, so candidates above one means the types genuinely differ. No assignability rule lives here and none should: this states one type per pair and comparing it to another is the asking reader’s predicate, the widenings worth admitting being a use-site question rather than a fact about a parameter.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the pair relation

site (CHARACTER VARYING, nullable)

which SDL site spelled the pair, in intent_argmapping_pair’s closed vocabulary of eight; with the use-site key and the position this is the grain, and it is what decided which of the two censuses answered

use_site (CHARACTER VARYING, nullable)

the consuming coordinate, serialized as intent_argmapping_pair serializes it; carried rather than re-spelled, which is why the arms here join that relation instead of the eight owner relations directly

position (INTEGER, nullable)

the pair’s 0-based position within its own argMapping list, completing the grain

param_name (CHARACTER VARYING, nullable)

the left side of the pair as the author wrote it, which is also the parameter name the match was made on

java_type (CHARACTER VARYING, nullable)

the parameter’s Java type, fully qualified: sql_routine_parameter.binding_type on the routine arm and jvm_method_parameter_type_ref.referenced_class at the root type path on the other seven. Qualified on both by construction, which is the whole reason the classpath arm reads the decomposition rather than the parameter row beside it; the view’s own comment states that. The root of the declared type and so the raw head of a parameterised one, List rather than List<Film>: a comparison caring about the element type descends that relation’s own type_path rather than asking for a second column here

candidates (INTEGER, nullable)

how many distinct types resolved for this pair, this row’s being one of them; 1 on an unambiguous parameter. Above one means an overload set or a doubly-declared class whose parameters of this name differ in type, which is a resolution nothing here picks between: a reader that must have one type requires 1, on intent_bound_table.candidates' terms

intent_argmapping_key_column_candidate (view)

The key column an argMapping binding of a node id projects out of the decoded key, with that column’s Java type beside it where the catalog can say: the name half of the projection resolution, before the type half decides whether the value can reach the parameter. Two arms over populations that are disjoint by the trailing-segment count, because there are two ways to arrive at one key column and they are one destination rather than two. The authored arm is a trailing segment naming a key column, which is the capability this family shipped with. The inferred arm is a binding that names no segment at all against a node type whose key is one column: nothing else it could mean, so the sole column is the projection and the author did not have to spell it. Whether a segment named it is provenance and not shape, readable from trailing_segment_name beside it, and both arms yield the same column with the same type reached the same way, which is what makes the emitted decode one emission rather than two. Their disjointness is arithmetic rather than a precedence: one trailing segment against zero, on the leaf’s own count. The inferred arm reaches arity through intent_resolved_node_key_shape rather than counting the key list here, so the arity this population turns on is the same number the decode relation’s slot arm turns on, and the sole column’s type comes off that relation’s own payload rather than being a second spelling of the same catalog reach. Two or more key columns is no row on either arm and the detection beside this states why: one binding carries one value, so there is nothing to infer. Split out from intent_resolved_node_key_projection rather than living inside it, and the split is what lets a type mismatch be its own verdict: the detection beside it states an unknown column as the absence of a row here and a type disagreement as a row here with no projected row, so the two arms are disjoint by construction and neither has to re-test the other’s predicate. Absent this relation, adding the type predicate to the projection’s own join would have collapsed both into the unknown-column message, which names the wrong thing and offers the wrong remedy: an author who spelled the column correctly would be told it does not exist. The name match is the membership condition and the type is a payload, which is why the reach for it is an outer join and its absence is a NULL rather than a missing row. Requiring it would have re-broken exactly what the split fixed, and for a case the key-column relation deliberately admits: the pinned-SDL tier answers with no table at all, its own comment saying that a name resolving against nothing is a row there and a detection elsewhere, so a pinned key column under an unbound or ambiguously-bound node type would have stopped being a candidate and been reported as a column that does not exist. It stays a candidate with no type, and the gate downstream stands aside. Case-insensitive on both crossings, the authored spelling against the resolved key column and the resolved key column against the catalog, which is the same convention each side already carries a generated fold for. The inferred arm crosses only the second of those, having no authored spelling to fold.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the binding leaf

site (CHARACTER VARYING, nullable)

which SDL site spelled the pair, in intent_argmapping_pair’s closed vocabulary of eight

use_site (CHARACTER VARYING, nullable)

the consuming coordinate, serialized as intent_argmapping_pair serializes it; with site and position the grain

type_name (CHARACTER VARYING, nullable)

the spelling site’s owning type

field_name (CHARACTER VARYING, nullable)

the spelling site’s field name within that type

position (INTEGER, nullable)

the pair’s 0-based position within its own argMapping list

argument_path (CHARACTER VARYING, nullable)

the path as written, carried so a message quotes the author’s own spelling

bound_kind (CHARACTER VARYING, nullable)

ARGUMENT where the decoded node id is a field argument, INPUT_FIELD where it is an input field reached below one; carried from the binding leaf

bound_type_name (CHARACTER VARYING, nullable)

the leaf’s owning type, carried from the binding leaf

bound_field_name (CHARACTER VARYING, nullable)

the leaf’s owning field on an ARGUMENT leaf, the input field itself on an INPUT_FIELD leaf

bound_argument_name (CHARACTER VARYING, nullable)

the argument’s name on an ARGUMENT leaf; NULL on an INPUT_FIELD leaf

node_type_name (CHARACTER VARYING, nullable)

the node type the leaf’s @nodeId names, as written

column_name (CHARACTER VARYING, nullable)

the projected key column, spelled as the winning key-column tier spells it rather than as the author wrote it, on intent_resolved_node_key_projection.column_name’s terms. The column a trailing segment matched on the authored arm, and the node type’s sole key column on the inferred one, where there was nothing to match against

key_position (INTEGER, nullable)

the projected column’s 0-based position within the node key; 0 on every inferred row, a one-column key having no other position

tier (CHARACTER VARYING, nullable)

which key-column population answered for this node type, carried from intent_resolved_node_key_column’s closed vocabulary of three

column_java_type (CHARACTER VARYING, nullable)

the column’s Java type as jOOQ binds it, fully qualified, from sql_column.binding_type: the type of the value the emitted record read yields, and the left operand of the agreement the projection requires. The binding type and not the SQL type, because what the emitted code hands the parameter is a Java value off a jOOQ record. NULL where the catalog cannot answer, which is a node type with no unambiguous table binding or a pinned key column the bound table does not have; the view’s own comment argues why that is a payload absence rather than a missing row, and the projection stands aside on it exactly as it does on an unresolved parameter type

leaf_named_type (CHARACTER VARYING, nullable)

the opened leaf’s own SDL named type, carried from the binding leaf so a message about this candidate need not re-join for it

leaf_is_list (BOOLEAN, nullable)

whether the opened node id is list-shaped, carried from the binding leaf. A list candidate is a real one, naming the list of this column across the decoded ids, and nothing here or in the detection rejects it; what stands between it and emission is that no emitter builds that shape yet, which is the consumer’s deferral to mint and the reason this column is carried rather than filtered on

trailing_segment_name (CHARACTER VARYING, nullable)

the segment the author spelled beyond the leaf to name this column, as written, or NULL where they spelled none and the arity inferred it. Which arm answered, therefore, and the only column that tells them apart, the two being one destination in every other respect. Carried here rather than re-joined by each reader because the authored arm already has the segment row in hand, and because the join that reached it downstream took the path’s last segment, which names the leaf itself once a binding with nothing trailing is also a candidate. A message quotes this where it is non-NULL, the author’s own spelling being what they can search for, and names column_name beside it where it is NULL, there being no authored spelling to quote

intent_argmapping_pair

Every argMapping pair any directive spells, in one shape: the seven pair relations of that family normalised onto the widest arm’s projection, with a site literal naming which one a row came from. Those relations are one shape only in their tail (position, param_name, argument_path); their use-site keys run from four columns to seven, so a reader over all of them either widens by hand or asks this. Naming it keeps the widening written once, which is the point: the arms are hand-written SELECTs over relations of differing key arity, a typo in one is exactly the drift a cross-site parity test exists to catch, and a second consumer re-spelling the union is how two readings of one population begin disagreeing. Every reader of a pair’s resolution therefore departs from here, and one needing an arm’s own extra key columns joins this relation on site plus the use-site key rather than parsing anything or re-assembling the union. Non-destructive by construction: it adds a discriminator and drops nothing, so an arm’s own relation stays where a reader of that site alone goes. The owning application’s source position is carried the same way and for the same reason: every arm reaches one by a join on its own key, all eight joins are inner (each pair relation has a foreign key onto its owner, the three step arms through their step relation), and a reader assembling that eight-way lookup for itself is exactly the drift this relation exists to prevent. It is what lets a detection over a pair’s resolution locate its message without knowing which of the seven relations the pair came from. Eight site values over seven relations, the field-condition relation being a shared coordinate whose owning type’s kind splits it into an output-field site and an input-field site with different heads and different emitters, which is how the capture side already tells those halves apart. The grain is the pair’s own with ordinal intact: @routine and @reference are repeatable and each application carries its own argMapping, so collapsing to one row per field coordinate would resolve one application’s paths and silently drop its siblings, which is the one move the nearest sibling view makes that this family must not. Materialized: this relation is a table refilled from intent_argmapping_pair_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from every arm’s own relation

site (CHARACTER VARYING, nullable)

which SDL site spelled this pair, in a closed vocabulary of eight: ROUTINE, SERVICE, FIELD_CONDITION, INPUT_FIELD_CONDITION, ARGUMENT_CONDITION, FIELD_REFERENCE_STEP, ARGUMENT_REFERENCE_STEP, REFERENCE_FOR_STEP. Seven relations and eight values, the two condition sites sharing one. The column a consumer switches on, and the one a test pins so a case reaching an arm is a case naming it

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, in intent_input_occurrence_path’s own vocabulary extended by two forms: Type.field for a field-grain site with the argument in parentheses after it, then #<ordinal> for a repeatable application and [<step>] for a step position within one. With site and position this is the relation’s grain, and it is the coordinate a rejection about a pair has to be able to name, an author told to change a definition-keyed fact needing to know which use site is asking. Serialized rather than assembled at each reader because a message needs one string and the components differ by arm; those components are columns beside it, so nothing ever parses this

type_name (CHARACTER VARYING, nullable)

the spelling site’s owning type; with the field below, the coordinate all seven relations lead with and the one graphitron_argument_path_segment anchors on

field_name (CHARACTER VARYING, nullable)

the spelling site’s field name within the owning type. An input field on the INPUT_FIELD_CONDITION arm, an output field on every other

argument_name (CHARACTER VARYING, nullable)

the argument the site sits on, on the two argument-grain arms (ARGUMENT_CONDITION, ARGUMENT_REFERENCE_STEP); NULL on the other six, whose sites sit on a field. Determined by site rather than independent of it, which is what makes the nullness a stated rule instead of a missing value

ordinal (INTEGER, nullable)

the owning application’s ordinal, on the four arms whose directive is repeatable (ROUTINE and the three step sites); NULL on SERVICE and the two condition sites, which are not repeatable and carry no ordinal

step_position (INTEGER, nullable)

the owning step’s 0-based position within its application’s path, on the three step arms; NULL on the other five, which have no step

position (INTEGER, nullable)

0-based position of the pair within its own argMapping list, carried unchanged from every arm; part of the grain, so an author’s duplicate parameter survives here as it does in the base relations

param_name (CHARACTER VARYING, nullable)

the left side of the pair: the Java or routine parameter the path binds to

argument_path (CHARACTER VARYING, nullable)

the right side as written, spelled exactly as the arm’s own relation spells it, so a pair reaches its own segment decomposition by joining graphitron_argument_path_segment on the coordinate and this column

source_name (CHARACTER VARYING, nullable)

the SDL file the owning directive application was captured from, joined from that application’s own relation rather than from the field: a rejection about a pair has to point at the argMapping the author wrote, and a repeatable directive’s second application sits on a line the field’s own position does not name. NULL where the application carries no position, on graphitron_routine.source_name’s terms. The pair itself carries no finer position, the eight owners recording the application and not the list entry, so two pairs of one application share a location and the message tells them apart by naming the entry

source_line (INTEGER, nullable)

source line of the owning directive application, 1-based per the graphql-java convention; NULL exactly where source_name is

source_column (INTEGER, nullable)

source column of the owning directive application, 1-based per the graphql-java convention; NULL exactly where source_name is

intent_argmapping_pair_live (view)

This states the rule and is evaluated on demand. The canonical name intent_argmapping_pair beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_argmapping_pair.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_argmapping_pair.graph_name, whose comment carries what the value means

site (CHARACTER VARYING, nullable)

the site of a row of this rule, materialized into intent_argmapping_pair.site, whose comment carries what the value means

use_site (CHARACTER VARYING, nullable)

the use_site of a row of this rule, materialized into intent_argmapping_pair.use_site, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_argmapping_pair.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_argmapping_pair.field_name, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_argmapping_pair.argument_name, whose comment carries what the value means

ordinal (INTEGER, nullable)

the ordinal of a row of this rule, materialized into intent_argmapping_pair.ordinal, whose comment carries what the value means

step_position (INTEGER, nullable)

the step_position of a row of this rule, materialized into intent_argmapping_pair.step_position, whose comment carries what the value means

position (INTEGER, nullable)

the position of a row of this rule, materialized into intent_argmapping_pair.position, whose comment carries what the value means

param_name (CHARACTER VARYING, nullable)

the param_name of a row of this rule, materialized into intent_argmapping_pair.param_name, whose comment carries what the value means

argument_path (CHARACTER VARYING, nullable)

the argument_path of a row of this rule, materialized into intent_argmapping_pair.argument_path, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_argmapping_pair.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_argmapping_pair.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_argmapping_pair.source_column, whose comment carries what the value means

intent_argmapping_projection_defect (view)

What is wrong with an argMapping binding that descends past an input object: one row per defective pair, in a closed verdict vocabulary of six, over the binding leaf and the resolved key columns alone. The rejections that close the silent hole this family had, where a path bound a node id and the base64 wire id went to the database verbatim with nothing in the build saying a word. Every arm is a positive statement about a captured population rather than a negative space maintained by hand: the leaf relation says what each path bound, whether that thing declares a decode, what type it is and how many names follow it, and these are the six ways such a path fails to become a projection. Which arm fires is decided by node_id_declared, trailing_segments and two existence tests against the candidate relation, one in each of two trailing-segment buckets, so the arms are disjoint by construction and no precedence rule is needed. Zero trailing segments under a declared decode is where the arity rule reaches this family, and BARE_NODE_ID is what is left of it. A one-column key needs no segment, the sole column being the only thing such a binding could project, so it resolves as an inferred candidate next door and draws no row here. What remains is a binding with nothing to infer, and there are three ways to be one. They share a verdict because the defect is one and differ in a clause the consumer composes from node_type_ref and the key list: a directive naming no type, so there is no key list to count; a named type resolving no key columns on any tier, so the count is zero; and a named type whose key is two or more columns, where one binding carries one value and nothing says which. The arm is spelled as the absence of a candidate rather than as an arity test of its own, which is the same anti-join UNKNOWN_KEY_COLUMN uses one bucket over, so what resolves and what is refused are decided by one relation and cannot drift into two arities that disagree. Exactly one trailing segment means the author named the column themselves, and then the resolution either succeeds (a row of intent_resolved_node_key_projection and no row here) or names what stopped it: MISSING_TYPE_NAME where the directive carries no typeName: and there is no containing table at this position to infer one from, UNKNOWN_KEY_COLUMN where the trailing segment matches no resolved key column of the named type, KEY_COLUMN_TYPE_MISMATCH where it matches one whose Java type the consuming parameter cannot take. That last arm is the one the arity rule widens rather than shrinks, and deliberately: it drives off the candidate relation, so an inferred candidate whose sole column disagrees with the parameter draws the same refusal an authored one does, and a binding the arity rule stopped rejecting for being bare is not thereby allowed to hand a parameter a value it cannot take. Which of the two ways the column was reached is trailing_segment_name’s to say, and it says it by being NULL. This relation is where all of it is decided, and that is the whole of the design rather than a convenience. The schema walk that mints the binding runs before capture, so it has no store to consult; a rule spelled there would be an earlier, unfalsifiable second copy of one of these arms, and it would win by rejecting first, which is exactly how a family ends up with two answers that agree until one changes. So the walk carries every segment it cannot resolve against SDL and judges none of them, and every judgment about them is here. Two arms exist because of that division and would otherwise look redundant. UNDECLARED_NODE_ID covers a path opening something with nothing to open: an ID carrying no @nodeId, and equally a String or an enum, the leaf_named_type column being what lets one message offer two remedies. TRAILING_SEGMENTS_BEYOND_ONE covers more names following the single key column a node id opens into, which is a typo or a nested form nothing here resolves. Two shapes deliberately stay out, and both are stated because each was once mistaken for an arm. A list-shaped node id with one trailing segment is not a defect: it names the list of that key column across the decoded ids, which is a coherent request, so it resolves as a projection and carries leaf_is_list, and what stands between it and emission is that no emitter builds that shape yet. And a projection that resolves at a site whose emitter is not wired is the same kind of fact. Both are deferrals rather than author defects, and whether an emitter exists is a fact about the generator’s own code and not about the schema, so their arms live with the consumer that knows the wired set (no.sikt.graphitron.rewrite.derive.ArgmappingProjectionDefects) rather than being asserted by a view that cannot see it. A pair that bound nothing at all also has no row: its head names no slot in scope, which is the one rejection the walk still owns because it is a question about the SDL surface in front of it rather than about captured facts. Every arm is use-keyed rather than definition-keyed, which is the point of resolving at the pair’s grain: one input type can be consumed by a routine call with no containing table and by a table-bound mutation where inference works, so an author told to add typeName: is being asked to satisfy a use-site constraint and the message has to name the use site that is asking. Locations are the owning directive application’s, carried from intent_argmapping_pair, so a message points at the argMapping the author wrote rather than at the input type’s declaration. There is no message column: the closed vocabulary plus the witness columns are the fact base, and the prose belongs with the consumer that composes it. Nor is there a rendered candidate list, though a message about a named type wants one: a consumer joining intent_resolved_node_key_column on the graph and node_type_ref gets the columns as rows in key order, and a render here would have to be split apart to be used, which is the one thing no reader of this schema does.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the binding leaf

site (CHARACTER VARYING, nullable)

which SDL site spelled the defective pair, in intent_argmapping_pair’s closed vocabulary of eight; with the use-site key and the position this is the grain, and it is what a message reads to name the directive the author wrote

use_site (CHARACTER VARYING, nullable)

the consuming coordinate, serialized as intent_argmapping_pair serializes it: the use site whose constraint is being violated, which a message about a definition-keyed remedy has to name so the author knows which consumer is asking

type_name (CHARACTER VARYING, nullable)

the spelling site’s owning type; with the field beside it, the coordinate a validation error attaches to

field_name (CHARACTER VARYING, nullable)

the spelling site’s field name within that type. An input field on the INPUT_FIELD_CONDITION arm, an output field on every other

position (INTEGER, nullable)

the defective pair’s 0-based position within its own argMapping list; part of the grain, so two defective pairs of one application are two rows rather than one

param_name (CHARACTER VARYING, nullable)

the left side of the pair, carried from intent_argmapping_pair so a message quotes the whole entry the author wrote rather than half of it

argument_path (CHARACTER VARYING, nullable)

the right side as written; quoted in the message beside the parameter, and the column the segment decomposition is reachable through

verdict (CHARACTER VARYING, nullable)

which defect, in a closed vocabulary of six: UNDECLARED_NODE_ID where a path opens something that declares no @nodeId and so has nothing to open, BARE_NODE_ID where a declared decode names no key column and none can be inferred, TRAILING_SEGMENTS_BEYOND_ONE where more names follow the one key column a node id opens into, MISSING_TYPE_NAME where a projection is asked for against a @nodeId carrying no typeName:, UNKNOWN_KEY_COLUMN where the trailing segment names no resolved key column of the named type, KEY_COLUMN_TYPE_MISMATCH where it names one whose Java type the consuming parameter cannot take. Disjoint by construction over two columns and two existence tests: node_id_declared splits the first off, trailing_segments (0, exactly 1, 2-or-more) splits the rest, the zero bucket keeps only what resolves no candidate, and within the one-segment bucket a typeName: test and then a candidate-row test separate the last three. The mismatch arm is the one that spans two buckets, driving off candidates rather than leaves, and its trailing_segments says which. This column is a discriminator a consumer switches on and never a precedence to re-test

bound_kind (CHARACTER VARYING, nullable)

ARGUMENT where the defective leaf is a field argument, INPUT_FIELD where it is an input field; carried from the leaf, and what tells a reader which @nodeId relation the directive sits on

bound_type_name (CHARACTER VARYING, nullable)

the leaf’s owning type, carried from the leaf: the type declaring the input field on an INPUT_FIELD leaf, the argument’s own owning type on an ARGUMENT one. With the two columns beside it, the @nodeId row’s own key, so a consumer wanting the directive’s own source position is one join away

bound_field_name (CHARACTER VARYING, nullable)

the leaf’s owning field on an ARGUMENT leaf, the input field itself on an INPUT_FIELD leaf

bound_argument_name (CHARACTER VARYING, nullable)

the argument’s name on an ARGUMENT leaf; NULL on an INPUT_FIELD leaf, whose key needs no argument component

node_type_ref (CHARACTER VARYING, nullable)

the typeName: the leaf’s @nodeId names, as written. NULL on every MISSING_TYPE_NAME row, that being the arm’s own condition, and NULL or not on a BARE_NODE_ID row, which selects between clauses of that arm’s remedy rather than making a second verdict. Never NULL on an UNKNOWN_KEY_COLUMN row, nor on a KEY_COLUMN_TYPE_MISMATCH one, both arms resolving against a named type

trailing_segment_name (CHARACTER VARYING, nullable)

the segment the author spelled beyond the leaf, as written: what the projection would have named. NULL on the whole BARE_NODE_ID arm, where there is no such segment, and NULL on a KEY_COLUMN_TYPE_MISMATCH row whose column the arity inferred rather than the author naming it, which is the one arm where the absence is a fact about how the column was reached rather than the arm’s own condition. Both are stated absences rather than missing values, and a consumer reading NULL here on a mismatch names the key column instead, the key list being one join away. Reached by position from the leaf rather than by splitting the path, and carried through the candidate relation on the mismatch arm so that "the segment beyond the leaf" and "the path’s last segment" cannot be confused once a leaf with nothing beyond it is also a candidate

leaf_named_type (CHARACTER VARYING, nullable)

the SDL named type of the thing the path tried to open, carried from the binding leaf. What separates the two remedies the UNDECLARED_NODE_ID arm has to offer: an ID is told to annotate it @nodeId(typeName:), anything else is told it has nothing to open at all. Present on every arm because it costs nothing and a message about any of them may name it

trailing_segments (INTEGER, nullable)

how many segments the path spells beyond the leaf, carried from the binding leaf: the column the arms are disjoint over, and what a TRAILING_SEGMENTS_BEYOND_ONE message quotes so the author sees how far past the one openable position they went. 1 or 0 on the mismatch arm, candidates existing in both those buckets, and it agrees with trailing_segment_name being non-NULL or NULL there rather than being a second fact

column_java_type (CHARACTER VARYING, nullable)

the projected column’s Java type as jOOQ binds it, fully qualified; the left operand of the comparison that rejected the pair. Non-NULL exactly on the KEY_COLUMN_TYPE_MISMATCH arm, that arm being the only one about a type, which is the stated absent bucket rather than a missing value on the other three. Carried rather than left to the consumer to resolve, so a message states the operands the join actually compared and cannot describe a different comparison than the one that fired

param_java_type (CHARACTER VARYING, nullable)

the consuming parameter’s Java type, fully qualified, from intent_argmapping_bound_parameter_type; the right operand, non-NULL exactly where the column beside it is

source_name (CHARACTER VARYING, nullable)

the SDL file the owning directive application was captured from, carried from intent_argmapping_pair; NULL where that application carries no position

source_line (INTEGER, nullable)

source line of the owning directive application, 1-based; NULL exactly where source_name is

source_column (INTEGER, nullable)

source column of the owning directive application, 1-based; NULL exactly where source_name is

intent_argmapping_segment_binding (view)

What each segment of an argMapping path binds to, one row per segment that names something reachable. The grain is the segment and not the path, which is the whole of the design: graphitron_argument_path_segment already says whether a segment exists at a position, so a position that has a segment and no row here means exactly one thing, it means it locally, and no verdict vocabulary is needed to say it. A path that stops halfway is therefore a prefix of rows rather than a stated silence, and the reader who wants to know where it stopped reads the last position that bound. One row per segment of every pair row of intent_argmapping_pair, at every site that spells an argMapping, which is what makes uniformity across @routine, @service and @condition structural rather than three call sites agreeing by discipline. A keying over intent_input_occurrence_path rather than a second walk of the input surface, joined through graphitron_argument_path_segment so neither the occurrence key nor the written path is ever split: the segment relation exists precisely so no reader has to, and a second decomposition here would be two spellings of one resolution that agree until one of them changes. The head is not always an argument, so position 0 has three arms, and which slots a head may name is the walk’s own rule read off the site: every argument of the field at a @routine, @service or output-field @condition, the pair’s own argument at an argument-site @condition, the pair’s own input field at an input-field @condition, and nothing at all at a path-step @condition, where no arm fires and the path binds nothing at any position. Positions below the head need no recursion, and that is what lets this be a view at all: every prefix of an occurrence path is its own row, so a segment at position j binds exactly when some occurrence path of depth j has every step matching the segment at the same ordinal, which is a join per position rather than a walk. The rows are prefix-dense by construction, since the prefix of a matching path matches too, so the bound positions of a pair are always 0 through some k with no hole; a reader may rely on that rather than checking for one. DISTINCT because the join is one-to-many in occurrence paths while the answer is one: two paths agreeing on the field names at ordinals 1 through j are descending the same input fields from the same root type, so their container types agree ordinal by ordinal and the tied rows cannot disagree. Two caveats the arms inherit. The occurrence expansion stops at a type already visited on the path, the classification walk’s own first-visit guard restated, so a cyclic re-entry contributes no step and a path that would have re-entered binds up to the last segment before the cycle and no further; that stop is load-bearing rather than incidental. And an input type no argument reaches has no occurrence row to descend, so a dotted input-field head binds at position 0 and nowhere below, which looks from here like any other path that stopped; the two are deliberately one fact at this grain, and a reader who needs them apart joins intent_input_occurrence_path_step to ask whether the head’s type is reached at all.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the pair relation

site (CHARACTER VARYING, nullable)

which SDL site spelled the pair, in intent_argmapping_pair’s closed vocabulary of eight; with the use-site key, the position and the segment position this is the grain, and it is what a consumer switches on to know whether an emitter is wired for the answer

use_site (CHARACTER VARYING, nullable)

the consuming coordinate, serialized as intent_argmapping_pair serializes it; the coordinate a rejection about this pair names, and the key a reader joins that relation on to recover the arm’s own components

type_name (CHARACTER VARYING, nullable)

the spelling site’s owning type, carried so the segment decomposition is one join away

field_name (CHARACTER VARYING, nullable)

the spelling site’s field name within that type

position (INTEGER, nullable)

the pair’s 0-based position within its own argMapping list

argument_path (CHARACTER VARYING, nullable)

the path as written, carried so a message can quote what the author wrote and so the segment rows are reachable without a second read of the pair

segment_position (INTEGER, nullable)

the bound segment’s 0-based position within the path, the same ordinal graphitron_argument_path_segment gives it. Position 0 is the head; the highest bound position of a pair is where the path stopped, and a segment existing one above it is a name that resolved to nothing

segment_name (CHARACTER VARYING, nullable)

the segment as the author spelled it, carried beside what it bound so a reader never re-joins the segment relation to say which name this row is about

bound_kind (CHARACTER VARYING, nullable)

ARGUMENT where the segment bound a field argument, which only position 0 can do and only at a site whose slots are arguments; INPUT_FIELD where it bound an input field, which is every position below the head and also position 0 at an input-field @condition. A closed two-value vocabulary, and the column saying which of the two @nodeId relations a reader joins to ask whether this binding carries one

bound_type_name (CHARACTER VARYING, nullable)

the bound thing’s owning type: the argument’s own owning type on an ARGUMENT binding, the input object declaring the field on an INPUT_FIELD binding

bound_field_name (CHARACTER VARYING, nullable)

the bound thing’s owning field on an ARGUMENT binding, and the input field itself on an INPUT_FIELD binding. With the columns around it this is the @nodeId relation’s own key, so a binding’s directive row and its source position are one join away

bound_argument_name (CHARACTER VARYING, nullable)

the argument’s name on an ARGUMENT binding; NULL on an INPUT_FIELD binding, whose key needs no argument component

intent_argument_column_match

Which column an argument’s own name resolves to on the table its site navigates to: the column a filter predicate built from that argument compares against. The argument-site counterpart of intent_column_match_claim, and deliberately not a claim. A claim view states a classification some coordinate is claimed by and unions with its siblings at the classifier grain, and no classifier vocabulary reaches an argument; what an argument gets from a resolved column is a predicate and not a kind, so these rows carry no classifier column and nothing reduces them. Everything else is the twin’s reading transcribed to this site. The argument’s named type has kind SCALAR or ENUM, which is the resolver’s own gate rather than an addition: an input-object argument expands into input fields that resolve at their own sites, so a name match against the argument itself would be a row no consumer asked for. The site resolves against exactly one table, the site being the argument together with that table, which is intent_argument_column_scope’s resolution and its grain; so every decline that relation makes is a silence here and this view adds none of its own. At a multi-table polymorphic root that means one row per branch on which the name reaches a column, and the per-branch divergence is where this relation earns the widened grain: a name reaching a column on one participant’s table and none on another’s is the classifier’s own per-participant rejection, which the walk states by lowering each branch and failing on the one that will not resolve, and which is here the difference between the branches intent_field_scope_table names for the coordinate and the ones this relation answers for. A detection over that pair rather than a column on either. The effective name is the @field(name:) binding where one was written, else the argument name, which is the resolver’s COALESCE, and the arm needs no undecoded-presence fallback for the reason the field-site view needs none: a declined decode leaves the COALESCE on the argument name, which is the fallback anyway. The match is two-tier, the generated Java name before the SQL name, both case-insensitive, collapsed to the first match in tier-then-ordinal order on the resolved table. On the table and not on the argument, and the difference is the whole content of this relation’s grain: what the collapse is for is two columns of one table answering one name, so partitioning it by the argument alone picks one branch of a multi-table polymorphic root and drops the rest. It did exactly that until the participant fan-out reached the scope below, which is the lesson a widened grain carries to every window over it. The scope drives the join and that is load-bearing rather than stylistic, on the measurement intent_column_match_claim’s comment carries: H2 re-evaluates a joined derived relation once per outer row, so reading the scope from underneath graphql_argument would cost the whole relation once per candidate argument, and every argument in the graph is a candidate. Absence is where a written name reaches no column on the resolved table, which is the resolver’s own unbound-argument rejection, and it is equally the ordinary answer for an argument whose content is not column-shaped at all. Nothing here tells those two apart, and what would is a defect relation over this one rather than a column on it. Materialized: this relation is a table refilled from intent_argument_column_match_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from graphql_argument

type_name (CHARACTER VARYING, not null)

the type owning the field the resolved argument sits on

field_name (CHARACTER VARYING, not null)

the field the resolved argument sits on

argument_name (CHARACTER VARYING, not null)

the resolved argument’s name within the owning field; part of the grain with the resolved table, the scope this reads keying the site that way

matched_name (CHARACTER VARYING, not null)

the effective name this resolved: the @field(name:) binding where one decoded, else the argument name. What the author wrote, so a diagnostic naming the unresolved spelling reads it here rather than deciding which of the two applied

matched_by (CHARACTER VARYING, not null)

which tier matched: JOOQ_NAME (the generated Java field name) or SQL_NAME. Makes the two-tier precedence observable rather than only its outcome

table_source_name (CHARACTER VARYING, not null)

witness: the resolved table’s catalog partition, the first column of the sql_column key this row names

table_schema (CHARACTER VARYING, not null)

witness: the resolved table’s SQL schema

table_name (CHARACTER VARYING, not null)

witness: the resolved table’s SQL name. Which navigation reached it is intent_argument_column_scope’s basis, and a consumer emitting the predicate needs both

column_name (CHARACTER VARYING, not null)

witness: the matched column’s SQL name. With the three columns above this is sql_column’s full key, so the column’s type and nullability are one join away

source_name (CHARACTER VARYING, nullable)

the argument’s own declaration file; the position a diagnostic would carry

source_line (INTEGER, nullable)

source line of the argument declaration, 1-based

source_column (INTEGER, nullable)

source column of the argument declaration, 1-based

intent_argument_column_match_live (view)

This states the rule and is evaluated on demand. The canonical name intent_argument_column_match beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_argument_column_match.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_argument_column_match.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_argument_column_match.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_argument_column_match.field_name, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_argument_column_match.argument_name, whose comment carries what the value means

matched_name (CHARACTER VARYING, nullable)

the matched_name of a row of this rule, materialized into intent_argument_column_match.matched_name, whose comment carries what the value means

matched_by (CHARACTER VARYING, nullable)

the matched_by of a row of this rule, materialized into intent_argument_column_match.matched_by, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_argument_column_match.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_argument_column_match.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_argument_column_match.table_name, whose comment carries what the value means

column_name (CHARACTER VARYING, nullable)

the column_name of a row of this rule, materialized into intent_argument_column_match.column_name, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_argument_column_match.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_argument_column_match.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_argument_column_match.source_column, whose comment carries what the value means

intent_argument_column_scope

Which table the column name written at an argument’s site resolves against: the argument’s own navigation, answered at every site where such a name resolves at all. The argument-site twin of intent_field_column_scope, and a second relation for the reason intent_argument_reference_step_target is one rather than that view with a column added: the departure differs. A field’s names resolve in the navigation off its own parent’s row, an argument’s in the navigation off the table its content binds against, which intent_argument_scope_table answers and which the argument of a root field has where the field-site rule would give it none. Two rules, disjoint rather than ranked, so this relation is a plain union with no windowed collapse over it and carries the one-row-per-site property its twin stands on. What counts as the site is the argument together with the table its content binds against, on intent_input_field_column_scope’s terms: a departure that is not a function of the coordinate puts the departing table in the key, and at a multi-table polymorphic root the argument’s scope is one table per branch rather than one table. So one row per argument is what a monomorphic coordinate has and not what the relation guarantees, and the property being kept is that no site resolves twice, not that no argument does. An authored @reference path resolves to its terminal element’s table, demanding the terminal reach exactly one table rather than exactly one row, so an element joining two tables by three keys still names its destination; an element that resolved to several rows all reaching one table is one row here, the arm taking DISTINCT over a projection that keeps only the table. An argument with no path element resolves in its own scope table, read from intent_argument_scope_table rather than restated, so the two spellings of that precedence cannot drift and the demands it makes hold here unchanged. One thing this relation does not inherit from its twin, and the difference belongs to the site rather than being a choice made here: repetition. A repeated @reference on a field composes an ordered chain and the field-site rule takes the first application. Repeated on an argument it is a conflict the resolver rejects outright, order composition having no meaning on an argument, so there is no first application to prefer and a site carrying two has no row here at all. The count is over the applications and not over their elements, so an author writing an empty one beside a real one is a conflict here too, which is the resolver’s own reading of that pair. Declining says "no answer", which is what a site the validator must reject deserves, where preferring one would encode a precedence the site does not have. An element-less @reference(path: []) is legal SDL and inert, and this relation reads it as the resolver does: the anti-join is on the path’s elements and never on the directive’s presence, so such a site takes the scope rule and resolves against the argument’s own table, which is the bare predicate a directive-less argument would have produced. Nothing here says the argument’s content is column-shaped, which is intent_argument_scope_table’s stance and holds one rung up: this relation answers where a name would resolve if one is written, and which arguments write one is each consumer’s own question. Two consumers ask different halves of that. intent_argument_column_match asks which column the name reaches; a predicate binding asks whether the resolved table is the one the field already selects from or somewhere a join away, which is basis read directly. Deriving the navigation once is what stops those two disagreeing at a path reaching two tables, where a presence test over the captured elements says "moved" and the resolution says "nowhere". Materialized: this relation is a table refilled from intent_argument_column_scope_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from both rules' base relations

type_name (CHARACTER VARYING, not null)

the type owning the field the argument sits on. Not the type whose binding started the navigation, which is the field’s named type: the difference from the field-site twin, where the two are one

field_name (CHARACTER VARYING, not null)

the field the argument sits on

argument_name (CHARACTER VARYING, not null)

the argument whose site this row resolves; part of the grain with the resolved table below, so two arguments of one field each get their own row and neither reader has to know they agree, and one argument resolving against a branch each of a multi-table polymorphic root gets one row per branch

basis (CHARACTER VARYING, not null)

which rule resolved this site, in a closed vocabulary of two disjoint rules: PATH_TERMINAL (an authored argument-site @reference path’s terminal element), ARGUMENT_SCOPE (the argument’s own scope table, no path element written). Also the fork a predicate binding takes, PATH_TERMINAL being exactly the case where the resolved table is not the one the field already selects from. Which rule answered underneath ARGUMENT_SCOPE is intent_argument_scope_table’s own basis and is deliberately not restated here, a reader wanting it joining the relation that states it; PARTICIPANT_TABLE there is what makes one argument resolve on several tables under this basis

table_source_name (CHARACTER VARYING, not null)

the resolved table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, not null)

the resolved table’s SQL schema

table_name (CHARACTER VARYING, not null)

the resolved table’s SQL name. With the two columns above this is sql_table’s full key, so the table’s columns are one join away

intent_argument_column_scope_live (view)

This states the rule and is evaluated on demand. The canonical name intent_argument_column_scope beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_argument_column_scope.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_argument_column_scope.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_argument_column_scope.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_argument_column_scope.field_name, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_argument_column_scope.argument_name, whose comment carries what the value means

basis (CHARACTER VARYING, nullable)

the basis of a row of this rule, materialized into intent_argument_column_scope.basis, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_argument_column_scope.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_argument_column_scope.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_argument_column_scope.table_name, whose comment carries what the value means

intent_argument_filter_role (view)

Which rule resolves what one argument contributes to the filter surface of the field it sits on. The argument-grain counterpart of the field-grain claim stratum, and the relation a consumer building a generated WHERE clause reads before it reads any of the rules' own relations, because what it needs first is which of them applies. The classifier’s argument switch is an ordered fork rather than a set of disjoint tests, so this is a ranked collapse and not a union: @orderBy first, then a pagination-role name, then an input-object type, then the node-id decode, then the name match. Stating it as a union would let a @lookupKey-marked @orderBy argument surface twice, and picking either row would be a precedence this relation invented; the rank is the switch’s own order transcribed. Absence is where no rule answers, and every one of those sites is a rejection’s population rather than an argument that quietly contributes nothing: an unresolvable name, a repeated @reference, an @asFacet-style misuse. What the roles mean. ORDER_BY and PAGINATE contribute no predicate at all, the ordering and pagination facts consuming those arguments; PAGINATE reads the four reserved names, which is a generator constant rather than a captured fact and so is stated here in the derivation where the capture doctrine puts such things. INPUT_EXPANSION means the contribution is the argument’s input type’s own fields, resolved at their coordinates and not at this one, so a reader following it changes grain. NODE_ID means the predicate’s columns come from the resolved node key rather than from a name, and the whole population is read off intent_node_id_instruction rather than off the directive: that relation already carries both readings, the authored @nodeId and the implicit one at an ID argument literally named id on a field returning a node type, with the node-type resolution and every decline it makes already applied. Restating either rule here was the first draft of this relation and it was wrong twice over, duplicating a rule the store states and getting the implicit one’s reach narrower than the store’s. What this relation adds is the wiring the instruction relation deliberately does not state: an instruction says the decode applies at a site, and whether the classifier can build a filter from it is a separate question with three exits. A @field(name:) binding beside it names two binding axes at once and the site resolves to nothing. On the implicit reading only, a column of that name on the argument’s own scope shadows it into nothing, a composite key without @lookupKey is unwired and resolves to nothing, and a list at arity one without @lookupKey falls through to the name match, which is the one exit that lands on another role rather than on silence. Those three are the implicit reading’s because the authored directive’s equivalents are the decode’s own forks, which intent_node_id_instruction and the decode relations below it already answer. A node type whose key resolves to nothing at all is read here as the single-column shape, which is the shape a node has when nothing says otherwise; such a type is a rejection’s population and no arity this relation could invent would change that. NAME_MATCHED means the predicate compares the column intent_argument_column_match resolved, and it covers the @reference-pathed argument and the plain one alike: the two are one rule here because the column resolution already tells them apart, its scope’s basis saying whether the predicate lands on the field’s own table or a join away. It also covers the argument of a multi-table polymorphic root, which it did not before the participant fan-out reached the column resolution: such a coordinate is rooted in one table per branch, the name resolves against each of them, and this relation had no row at all where the classifier lowers a predicate per branch. Which is where the grain of this relation and the grain below it deliberately part. The rule an argument falls under is the argument’s and is the same on every branch, so this stays one row per argument, and the branch-specific answer, which column on which table, is the resolution’s to give; a reader assembling a branch’s filter surface joins the match on the table it is assembling for. That division is the one this relation already declares for the monomorphic case, that it chooses the rule and does not assemble the predicate, and the fan-out only makes the reason visible. Two consequences worth stating rather than leaving to be met. A name that reaches a column on one participant’s table and none on another’s carries NAME_MATCHED here on the strength of the branch that resolved, which is a rejection’s population and reads as one only against the match rows, per the reading of absence this relation already takes. And the implicit node id’s shadowing modifier is an existence test over those same rows, so it reads "shadowed on some branch"; branches disagreeing on it is the same detection over the same pair, not a second vocabulary here. Two columns beside the role are modifiers and not arms, because the classifier treats them that way. lookup_key says the argument is consumed by the keyed lookup instead of the WHERE clause, which it can be on the node-id and name-matched roles alike, so folding it into the vocabulary would have split two roles into four. suppressed says an override cascade suppresses the generated predicate, from @condition(override: true) on the field or on the argument; it is not an absence because a suppressed argument carrying its own @condition still contributes that authored filter, and on an INPUT_EXPANSION row it is the cascade’s starting value for the walk into the input type. What this relation does not state is the predicate itself. Which column, which comparison and which reach are the resolution relations' answers, read through the role; putting them here would make this a filter-surface relation at the wrong grain, an argument being where the rule is chosen and not where the predicate is assembled.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_argument

type_name (CHARACTER VARYING, nullable)

the type owning the field the argument sits on

field_name (CHARACTER VARYING, nullable)

the field the argument sits on

argument_name (CHARACTER VARYING, nullable)

the argument’s name within the owning field; the grain, one row per argument any rule answers for

role (CHARACTER VARYING, nullable)

which rule resolves the contribution: ORDER_BY, PAGINATE, INPUT_EXPANSION, NODE_ID or NAME_MATCHED, the winner of the ranked fork. A closed vocabulary, and a new classifier arm is a new value here rather than a silence

lookup_key (BOOLEAN, nullable)

@lookupKey on the argument: the value is consumed by the keyed lookup rather than by the WHERE clause. A modifier on the role and not a role, because the classifier reads it inside several arms rather than instead of them

suppressed (BOOLEAN, nullable)

an override cascade suppresses the generated predicate: @condition(override: true) on the field or on the argument. Not an absence, an argument carrying its own @condition still contributing that authored filter; on an INPUT_EXPANSION row it is what the walk into the input type starts from

source_name (CHARACTER VARYING, nullable)

the argument’s own declaration file; the position a diagnostic would carry

source_line (INTEGER, nullable)

source line of the argument declaration, 1-based

source_column (INTEGER, nullable)

source column of the argument declaration, 1-based

intent_argument_reference_step_hop (view)

One argument-site @reference path element’s local resolution: the field-site sibling’s rule at the other coordinate a @reference can be written on. Every arm, every namespace precedence and every orientation is that view’s, and its comment is where they are argued; what differs here is only the relation the elements come from and the key they are keyed by, an argument being its own site. A sibling relation rather than an argument_name column on the field-site view, on the discipline intent_input_occurrence_path_step states for its own shape: the two sites' coordinates are different lengths, so one relation over both would carry a column that is NULL by kind on half its rows and every reader of either site would then have to say which kind it meant. Two relations say it once each. The duplication is the SQL body and not the rule, which is the trade this schema makes wherever a rule is coordinate-shaped: a reader comparing the two finds them textually identical arm for arm, and the anchor test asserts that the two answer the same path shape the same way rather than leaving the agreement to inspection. Where a resolution genuinely is shared it is already a relation of its own and both views join it, intent_spelled_table for a written table name and intent_name_matched_key_pair for a function result’s column pairing, so what remains here is the coordinate-shaped part alone. Separate from intent_argument_reference_step_target for the reason its field-site counterpart is: the local resolution has no recursion in it, and keeping the two apart lets that view’s recursive term be a single join rather than a copy of these arms.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_argument_reference_step

type_name (CHARACTER VARYING, nullable)

the type owning the field the argument sits on

field_name (CHARACTER VARYING, nullable)

the field owning the argument the @reference is applied to

argument_name (CHARACTER VARYING, nullable)

the argument the @reference is applied to; the coordinate column the field-site sibling does not have, and the reason this is its own relation

ordinal (INTEGER, nullable)

the owning @reference application’s ordinal. Carried for parity with the field-site sibling and with the captured relation’s own key, not because an argument composes a chain: repeated @reference on an argument is a stated conflict rather than an ordered composition, order having no meaning at a site that is not a projection

position (INTEGER, nullable)

the element’s 0-based position within its application’s path

via (CHARACTER VARYING, nullable)

which arm resolved the element: KEY, TABLE or NAME_MATCH, as on the field-site sibling

key_matched_by (CHARACTER VARYING, nullable)

for a KEY hop, which namespace answered: SQL_NAME or JOOQ_NAME. NULL on a TABLE or NAME_MATCH hop, as on the field-site sibling

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition, first column of its sql_table key

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name; a candidate departure, not yet a fact about the chain

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name

constraint_name (CHARACTER VARYING, nullable)

the foreign key the hop joins on, named or discovered; NULL on a NAME_MATCH hop, as on the field-site sibling

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key, FALSE when the arriving one does; NULL on a NAME_MATCH hop, as on the field-site sibling

intent_argument_reference_step_target (view)

Where each element of an argument-site @reference path actually lands: intent_argument_reference_step_hop walked one element at a time, so a row exists only for an element the chain can be shown to reach. The field-site sibling’s comment argues the walk, and everything it says about recursion, about absence meaning "not reached" rather than "resolves to nothing in particular", and about an element naming neither key nor table not being a hop this view knows, holds here unchanged. One thing does not, and it is the whole reason this view is not that one with a column added: the departure. A field-site path departs from the enclosing type’s own binding, because the field is a projection off that type’s row. An argument-site path departs from the table the argument’s own content binds against, because an argument filters what the field returns rather than what its parent is; the resolver states the same thing by passing the field’s target table as the path’s source. So a filter argument on a root field, whose parent type is bound to nothing at all, has a departure here where the field-site rule would give it none, and reading one view for both sites would have made that departure a case rather than the rule. That departure is intent_argument_scope_table’s whole subject and is read from it rather than restated: the field’s binding read through intent_field_navigated_type so a connection-returning field departs its element type’s table and not the wrapper’s, and below it the @mutation(table:) spelling, which is what gives a delete surface’s argument a departure at all where its return type binds nothing. Reading the relation rather than spelling the upper rung inline is also what stops the two spellings of one rule from drifting, the rule having a second reader now. It costs one demand the earlier spelling did not make, and the demand is the scope relation’s and correct: a departure is a table a predicate is emitted on, so an ambiguously bound named type is no departure rather than two, which is intent_field_reference_discovery’s stance on the same question. The field-site sibling still admits the ambiguity, its departure being the enclosing type’s binding read directly and its arities counting what that reached. It gains one shape from the same relation and does not yet answer it fully, which is stated here rather than left to be discovered: an argument on a field returning a multi-table polymorphic container departs from one table per branch, so such a path is walked once per branch and each walk lands wherever that branch’s own keys reach. The rows come out; the two arity columns do not follow. They are counted per element and position and not per departure, so two branches walking the same element at the same position fall in one partition and their candidate counts are conflated, which would read as an ambiguity at a step that is unambiguous on each branch taken alone. Putting the departure in that partition is what would close it, and it is not done here because it would also split the candidate set at an ambiguous mid-chain landing, which is a change to what the arity means on a shape the tree does exercise. No graph in the tree writes an argument-site path at such a coordinate, so this is an unexercised limit rather than a wrong answer anybody reads, and it is the first thing to fix for whoever needs one.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the hop view

type_name (CHARACTER VARYING, nullable)

the type owning the field the argument sits on. Not the type whose binding started the chain, which is the field’s named type: the difference from the field-site sibling, where the two are one

field_name (CHARACTER VARYING, nullable)

the field owning the argument the @reference is applied to; also the field whose named type’s binding started the chain

argument_name (CHARACTER VARYING, nullable)

the argument the @reference is applied to

ordinal (INTEGER, nullable)

the owning @reference application’s ordinal, as on the hop view

position (INTEGER, nullable)

the element’s 0-based position within its application’s path; positions are contiguous from 0 up to wherever the chain stopped

via (CHARACTER VARYING, nullable)

which arm resolved the element, as on the hop view: KEY, TABLE or NAME_MATCH

key_matched_by (CHARACTER VARYING, nullable)

for a KEY element, the namespace that answered; NULL on a TABLE or NAME_MATCH element. As on the hop view

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition; the argument’s own scope table at position 0, the previous element’s arrival after that

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name. At the path’s last position this is the table the argument’s own column name resolves against, which is where a filter predicate binds

constraint_name (CHARACTER VARYING, nullable)

the foreign key this element joins on, named or discovered; NULL on a NAME_MATCH element, as on the hop view

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key; the element’s direction. NULL on a NAME_MATCH element, as on the hop view

targets (INTEGER, nullable)

how many distinct tables this element reaches, this row’s arrival being one of them; 1 where the destination is certain. Separate from candidates for the reason the field-site sibling states: an element with three foreign keys connecting the same pair of tables reaches one table by three routes, and a reader that only needs the destination can trust that where one that has to render the join cannot

candidates (INTEGER, nullable)

how many rows this element resolved to, counting routes and not just destinations; 1 is the requirement for an expressible hop

intent_argument_scope_table

Which table an argument’s column-shaped content binds against: the table a predicate built from this argument correlates on, and the table a @nodeId or @reference path departs from. The field’s scope fanned out over the field’s arguments and nothing else: the rule is intent_field_scope_table’s, which is where the two ranked rungs, the disjoint participant arm and every demand any of them makes are documented, and this relation adds only the argument key. The argument and the table together are the grain, because the relation it fans out is keyed that way: a field whose named type is a multi-table polymorphic container is rooted in one table per branch, so each of its arguments binds against each of those tables and each pair is a predicate the generator emits. One row per argument is therefore the ordinary case and not the rule, and a reader that assumed it would silently take one branch of a coordinate that has several. It exists as its own relation because that key is what four readers join on and because a predicate is emitted per argument, so the fan-out is the shape every consumer here wants; it does not exist because an argument’s scope is a different question from its field’s. It was once spelled the other way round, the whole rule stated here and evaluated once per argument, and the fold over the condition membership is what found that: a @condition on a field with no arguments has a table to filter and no argument to carry it, so the rule had to be stated at the grain it was always about before anything could read it there. Nothing here says the argument’s content is column-shaped: this relation answers where it would bind if it is, and which arguments carry such content is each consumer’s own question. Materialized: this relation is a table refilled from intent_argument_scope_table_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in intent_field_scope_table; these rows are the fan-out of what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_argument, which is the relation the fan-out drives from

type_name (CHARACTER VARYING, nullable)

the type owning the field the argument sits on

field_name (CHARACTER VARYING, nullable)

the field the argument sits on

argument_name (CHARACTER VARYING, nullable)

the argument whose scope this row states; part of the grain with the table below, so two arguments of one field each get their own row and neither reader has to know they agree, and one argument of a multi-table polymorphic root gets one row per branch it binds against

basis (CHARACTER VARYING, nullable)

which rule answered, carried unchanged from intent_field_scope_table, whose comment says what the four values mean. Every argument of one field carries the same value, and every branch of one argument does too, the rule being the field’s and not the argument’s or the branch’s; a reader wanting one of them filters on it and owns having chosen

table_source_name (CHARACTER VARYING, nullable)

the scope table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the scope table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the scope table’s SQL name; with the two columns above this is sql_table’s full key, so the table’s own columns and constraints are one join away

intent_argument_scope_table_live (view)

This states the rule and is evaluated on demand. The canonical name intent_argument_scope_table beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_argument_scope_table.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_argument_scope_table.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_argument_scope_table.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_argument_scope_table.field_name, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_argument_scope_table.argument_name, whose comment carries what the value means

basis (CHARACTER VARYING, nullable)

the basis of a row of this rule, materialized into intent_argument_scope_table.basis, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_argument_scope_table.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_argument_scope_table.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_argument_scope_table.table_name, whose comment carries what the value means

intent_authored_claim_conflict (view)

The authored-claim conflict rule as a resident of the intent_ stratum: one row per violated coordinate, both grains, the store-native pilot of the diagnostics stratum’s derivation arms. A coordinate violates when two or more distinct classifiers claim it, and that is the whole predicate: the relation is total over the authored claims and carries no population filter of its own. An authored contradiction is a contradiction wherever it sits, so each consumer applies the population its own question needs (the build-error surface joins intent_type_domain, type grain directly and field grain through the claim’s owning type, because only the emitted surface can fail a build; the editor’s diagnostic arm reads these rows ungated, a type no field reaches being precisely where an author most needs the signal). What this relation does not carry is any accept line: a filter wearing the view’s name would substitute one consumer’s population for the fact. Nor does it carry the claiming directives or the violation’s message. The claims are rows on the two claim views under this relation’s own key, so a consumer wanting their names joins them and asks membership as well as set equality; the message is a render whose naming order is AuthoredClaim’s declaration order, which is not a captured fact and so is no view’s to express, and it is minted post-capture into intent_authored_claim_rejection instead. One piece of Java logic still lives in this SQL and is pinned by the registered agreement anchor (no.sikt.graphitron.rewrite.derive.AuthoredClaimConflictsTest): the routine-plus-lookup carve-out, exactly that claim pair being the recognised-but-unsupported combination, which yields DEFERRED instead of CONFLICT. Locations join as the legacy mint did: a field violation carries the field’s own declared position, a type violation the type’s base declaration site at merge ordinal 0.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the claim views

type_name (CHARACTER VARYING, nullable)

the violated coordinate’s owning type (the coordinate itself at the type grain)

field_name (CHARACTER VARYING, nullable)

the violated coordinate’s field name; NULL exactly on type-grain rows, the two-grain union’s key shape (graphql_directive_site’s member_name precedent)

verdict (CHARACTER VARYING, nullable)

CONFLICT for mutually exclusive claims, DEFERRED for the recognised routine-plus-lookup pair; a closed two-value vocabulary the reduction’s own output type discriminates

source_name (CHARACTER VARYING, nullable)

the violated coordinate’s own declaration file (the field’s position at the field grain, the base declaration’s at the type grain); NULL where the declaration carries no position

source_line (INTEGER, nullable)

source line of the violated coordinate’s declaration, 1-based

source_column (INTEGER, nullable)

source column of the violated coordinate’s declaration, 1-based

intent_authored_claim_rejection

The rejection each row of intent_authored_claim_conflict mints, minted post-capture rather than derived: one row per violated coordinate, carrying the sealed Rejection hierarchy’s verdict on it and the message a report would print. A table because no view over this store can state the rule. The render’s input is AuthoredClaim’s declaration order, which is the conflict messages' fixed naming order and is not a captured fact of any graph, so the derivation has no relational statement and the enum’s own home in Java is the only place the order can be read without a copy of it going stale. Written by a capture-cadence writer that clears its graph partition and re-mints after every flush, on intent_type_backing_class’s cadence exactly, so on any settled store these rows stand one-to-one with the conflict view’s and the diagnostics arm reads them by inner join. Every column here is a projection of one Rejection value: kind is RejectionKind.of, variant the leaf class’s stored spelling, message what ValidationError’s coordinate prefix wraps around the rejection’s own text. That is what makes the diagnostics arm over this relation look like its captured siblings rather than like a render assembled in SQL, and it is what binds the two class-valued spellings to the classes they name, a SQL literal spelling a Java class being a copy nothing checks. Not rejection_, whose charter is the legacy walk’s verdicts and whose retirement clock is the walk’s: these rows are the store-native detection’s own, and they outlive it.

Primary key: (graph_name, ordinal). Foreign key: (graph_name) references store_graph (graph_name). Check: "KIND" IN('INVALID_SCHEMA', 'DEFERRED').

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

ordinal (INTEGER, not null)

mint order over the graph’s violated coordinates, 0-based; the key’s tie-breaker on rejection_validation_error.ordinal’s convention, which this relation needs because its natural key is the coordinate pair and that pair carries a NULL at the type grain where a key may not

type_name (CHARACTER VARYING, not null)

the violated coordinate’s owning type, joining intent_authored_claim_conflict’s own

field_name (CHARACTER VARYING, nullable)

the violated coordinate’s field name; NULL exactly on type-grain rows, the two-grain shape the conflict view is keyed by

kind (CHARACTER VARYING, not null)

RejectionKind.name() for the minted rejection, a closed CHECK over the two values this family can reach: INVALID_SCHEMA for the mutual-exclusivity conflict, DEFERRED for the recognised routine-plus-lookup pair. Minted rather than mapped from verdict in SQL, because the projection is RejectionKind’s and a CASE restating it here would be a second copy of a fork the hierarchy already owns

variant (CHARACTER VARYING, not null)

the minted rejection leaf’s class name with its package stripped, enclosing classes kept, on rejection_validation_error.variant’s spelling rule and through the same one Java site, so the two relations cannot spell one family two ways and a rename cannot leave a stale spelling behind

message (CHARACTER VARYING, not null)

the violation’s full report message, coordinate prefix included, byte-identical to what the report carries for this family (the agreement anchor pins the spelling); display material, never a dimension

intent_authored_field_claim (view)

The author’s field-grain classification claims. One arm pair per claiming directive (@service, @externalField, @nodeId, @lookupKey, @routine, @mutation): the decoded arm reads the semantic relation, the presence arm falls back to the raw application where the decode declined. The per-arm type_name masks transcribe the walk’s per-position detector gates: @service claims at every position, @externalField and @nodeId nowhere on a root, @routine not on Mutation or Subscription (a Mutation @routine is the walk’s own typed deferral, never a conflict slot), @lookupKey only on Query, @mutation only on Mutation. The @lookupKey arm fires on the whole argument surface, matching LookupFacts.triggersFor: a directly marked argument, or an argument whose named type is in the transitive lookup-bearing input closure (the recursive path-guarded closure above, seeded from the retired input-field site, so on accepted schemas the recursion never expands). That closure recurses over input_object_field_edge, the field edges deduplicated to the pairs they denote, and not over graphql_field: the hop joins on the named type and projects the declaring type, so two fields of one named type are identical output rows that UNION ALL keeps and re-expands at the next hop, doubling the frontier per level of input-object nesting. Consumption is through EXISTS, so deduplicating the edges changes no answer. The @routine arms collapse the repeatable ordinal grain to the minimum-ordinal application’s row.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried through from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the claimed field’s owning type

field_name (CHARACTER VARYING, nullable)

the claimed field’s name within the owning type

classifier (CHARACTER VARYING, nullable)

the classification kind the claim is for; a closed vocabulary the reading side decodes into a typed value (SERVICE, EXTERNAL_FIELD, NODE_ID, LOOKUP_KEY, ROUTINE, MUTATION), separate from the trigger because a derived claim may have no directive at all

trigger (CHARACTER VARYING, nullable)

the claiming directive’s name, without the leading @; what a conflict message names

decoded (BOOLEAN, nullable)

TRUE from a semantic-relation arm; FALSE from a presence arm, meaning the application exists but its decode declined

source_name (CHARACTER VARYING, nullable)

the claiming application’s own position; NULL on a closure-triggered @lookupKey claim, whose application sits on a remote input field

source_line (INTEGER, nullable)

source line of the claiming application, 1-based

source_column (INTEGER, nullable)

source column of the claiming application, 1-based

intent_authored_type_claim (view)

The author’s type-grain classification claims: @table and @error, decoded arm plus presence fallback each, with the root names masked out (transcribing the walk’s root short-circuit, which classifies a root before any type directive is read). That a conflict here can only occur on an OBJECT is guaranteed upstream by assembly (@error is declared on OBJECT), the same assembly dependency graphitron_undecoded_argument records; a lone @table claim on an INPUT_OBJECT or INTERFACE is an honest single claim that conflicts with nothing. The applications sit at the type grain even when applied on an extension site; the presence arms collapse a base-plus-extension double application to the minimum-ordinal row.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried through from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the claimed type

classifier (CHARACTER VARYING, nullable)

the classification kind the claim is for; a closed vocabulary the reading side decodes into a typed value (TABLE, ERROR), separate from the trigger because a derived claim may have no directive at all

trigger (CHARACTER VARYING, nullable)

the claiming directive’s name, without the leading @; what a conflict message names

decoded (BOOLEAN, nullable)

TRUE from a semantic-relation arm; FALSE from a presence arm, meaning the application exists but its decode declined

source_name (CHARACTER VARYING, nullable)

the claiming application’s own position file

source_line (INTEGER, nullable)

source line of the claiming application, 1-based

source_column (INTEGER, nullable)

source column of the claiming application, 1-based

intent_bound_table (view)

Which catalog table an @table-bearing type is bound to: graphitron_table’s reference resolved through intent_spelled_table, one row per candidate table. The reference is the name argument as written, or the type name where the argument was omitted, which is the derivation graphitron_table.table_ref’s own comment defers; how a spelling then meets the census is the spelling view’s rule, stated once there and not restated here. What this view adds over that one is the keying: a type, not a string, which is what every reader of a binding actually holds. The three root names are masked, transcribing the walk’s root short-circuit that classifies a root before any table binding is read, which is the same mask the authored type claims carry. A base derivation rather than a resolved_ reduction: it stands directly on a transcription pair and nothing reduces over sibling views to produce it. It is one arm of such a reduction, intent_resolved_type_binding coalescing it with the binding a @routine chain’s return derives, and that is where a reader asking which table stands for a type points; this relation answers the narrower question of what the author wrote @table for, which is what an editor locating a written site and any reader of the directive population itself asks. Ambiguity is rows, never a decline: two candidates are two rows and the count says so, so a reader can transcribe the walk’s Ambiguous verdict (require candidates = 1, as the column-match classifier does), offer every candidate (as an editor does, since each is a table the author might mean), or report the ambiguity, without any of them re-spelling the resolution. The reference as written and the application’s position are one join back to graphitron_table, which holds both.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_table

type_name (CHARACTER VARYING, nullable)

the @table-bearing type whose binding this row resolves

table_source_name (CHARACTER VARYING, nullable)

the resolved table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the resolved table’s SQL schema; what tells two candidates of one name apart

table_name (CHARACTER VARYING, nullable)

the resolved table’s SQL name. With the two columns above this is sql_table’s full key; the table’s other facts (its jOOQ name, its generated class, its comment) are one join away, per the referenced-side discipline sql_referential_constraint states

candidates (INTEGER, nullable)

how many tables the reference resolves to, this row being one of them; 1 on an unambiguous binding. Carried through from the spelling view rather than recounted here, and stated as a column rather than left to each reader’s own count, because whether a binding is ambiguous decides the reading (a claim declines, an editor offers every candidate) and a reader that counted for itself would be re-deriving the resolution’s own arity

intent_carrier_data_field

Where a mutation payload’s data arrives: for each OBJECT type a mutation-root write field returns, that type’s data channels, with the shape each element declares and how many channels the type has. A carrier is a payload whose whole job is to wrap one produced value beside an error channel, and the coordinate this relation names is where that value lands, which is what a surface offering or judging the $source sigil is asking about. The producing directive decides the family and the family decides two policies, so it is a column and not a filter this view applies for one reader: @service on a mutation-root field is SERVICE, @mutation is DML, @routine is ROUTINE, and a payload two families both return is a row per family rather than a pick. Errors-shaped fields are not data channels and never counted as one, and which fields those are is intent_errors_field’s to say rather than a condition spelled here: this relation is that one’s second reader, which is what promoted the shape out of a CTE inside this view and into a relation of its own. What a data channel’s element declares is one of three kinds, tried in the walk’s own order: a named type bound unambiguously to a table is TABLE, a named type the backing closure reaches is RECORD, and the ID scalar is ID. The closure arm is read on declared_via so a @table type’s own record class cannot answer here, that population being the first arm’s and an ambiguous binding being no binding at all. That arm inherits the closure’s own stated departure, and it costs this relation the two-level carrier: where a payload wraps a result type the producer’s class stands for, the closure backs the wrapper and the walk reaches past it, so the element resolves to no kind and the payload names nothing. The departure is the closure’s to close, not a second reading of it here. An element of any other kind is not a payload shape the generator admits, and it rejects the whole payload rather than just its own coordinate, so a type carrying one contributes nothing; the same holds for a data-channel directive that routes the type out of the carrier mold, and for the two ID-element refusals that are a family’s own (a routine write has no PK-echo shape, so ROUTINE admits no ID element at any wrapper, and a DELETE echo cannot have a nullable slot, so DML refuses [ID]). The arity is a column and the refusal is the reader’s, as on the discovery view: a payload declaring two data channels is two rows counting two, which is the coordinate the generator rejects for having no single data field, and a reader demanding data_fields = 1 transcribes that refusal without re-counting. Absence covers several things and none of them is "this payload has no data": no mutation-root field returns the type, or the type is not an OBJECT, or one of the rejections above dropped it. Element kind and family are columns for the same reason the arity is: which rows admit a given surface is that surface’s rule, and the $source sigil’s reader demands SERVICE and a TABLE or ID element, those being the producer the user manual names and the two elements the carrier classification encodes the upstream value onto. Materialized: this relation is a table refilled from intent_carrier_data_field_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the producing field

type_name (CHARACTER VARYING, nullable)

the payload type the producing field returns; the type whose data channels these rows are

field_name (CHARACTER VARYING, nullable)

the data channel’s field name within the payload type; the coordinate an author’s cursor sits on

family (CHARACTER VARYING, nullable)

which producing directive returns the payload, a closed three-value domain: SERVICE (@service), DML (@mutation), ROUTINE (@routine). Provenance and policy both, the two rejections that differ between families being this column’s; a payload two families return is a row per family, and a reader that means one of them filters on it

element_kind (CHARACTER VARYING, nullable)

what the channel’s element is, a closed three-value domain: TABLE (the named type is bound to one catalog table), RECORD (the backing closure reaches a class for it), ID (the ID scalar, the encoded-key echo). Never NULL here, an unrecognized element having dropped its whole payload

data_fields (INTEGER, nullable)

how many data channels the payload declares, this row being one of them; 1 is what a carrier requires, and a larger number is what the generator’s own "require exactly one" rejection counts. Stated as a column rather than left to each reader’s count, because whether the payload is a carrier at all decides the reading and a reader that counted for itself would be re-deriving the scan’s arity

intent_carrier_data_field_live (view)

This states the rule and is evaluated on demand. The canonical name intent_carrier_data_field beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_carrier_data_field.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_carrier_data_field.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_carrier_data_field.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_carrier_data_field.field_name, whose comment carries what the value means

family (CHARACTER VARYING, nullable)

the family of a row of this rule, materialized into intent_carrier_data_field.family, whose comment carries what the value means

element_kind (CHARACTER VARYING, nullable)

the element_kind of a row of this rule, materialized into intent_carrier_data_field.element_kind, whose comment carries what the value means

data_fields (INTEGER, nullable)

the data_fields of a row of this rule, materialized into intent_carrier_data_field.data_fields, whose comment carries what the value means

intent_carrier_routine_hop (view)

The hop a routine write’s payload carrier takes to re-read its committed row, for a data field that declares no path. A @routine write on a mutation root may return a payload wrapping one data field beside an error channel; the routine call is the write, and the data field owns the post-commit re-read. That hop is inferred from the payload’s shape rather than written, which is precisely why intent_field_reference_step_hop holds no row for it: that relation’s population is authored path elements, and this coordinate authors none. So the same keying rule is reached from two relations, and it lives in neither of them. This one states the two ends and joins intent_name_matched_key_pair for the pairing, exactly as the authored arm does, and for the reason the referenced-side discipline gives: the pairs are reachable from the triples this row already carries, and repeating them here would be a denormalisation. The departure is the routine the producing mutation field names, resolved as any written table name is and then required to be FUNCTION-typed. The arrival is the data field’s own named type’s binding, demanded unambiguous, an arrival that is not certain not being the one the re-read would run against. The producing field is required to carry no @reference, which is not a narrowing but the carrier’s own boundary: the chained form returns the terminus table type and has an authored element to resolve through, and @routine with @reference over a carrier return is rejected outright, so a row here would name a hop the generator will not emit. Ambiguity is rows, and here it is a real one the generator currently hides: two mutation fields returning one payload are two candidate departures, where the grounding memo keeps whichever field classified first. Absence covers several things and none of them is "this carrier has no hop": the payload is not a carrier, or its element is not table-backed, or its data field’s type binds ambiguously, or the routine name resolves to nothing FUNCTION-typed. One narrowness is inherited rather than chosen. The element_kind gate is intent_carrier_data_field’s, and that relation reads the @table population alone where this one reads the resolved binding, so a data field whose type is bound only by being what a routine returns is excluded upstream of here; the gate follows that relation when it moves, rather than this one reading past it.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the carrier relation

type_name (CHARACTER VARYING, nullable)

the payload type the producing mutation field returns; the carrier whose data field this hop serves

field_name (CHARACTER VARYING, nullable)

the data field within that payload: the coordinate the re-read runs at, and the one an author would hang a path on if the data field admitted one

from_source_name (CHARACTER VARYING, nullable)

the routine result’s catalog partition; the departure, resolved from the producing field’s @routine(name:) through the spelling view

from_schema (CHARACTER VARYING, nullable)

the routine result’s SQL schema

from_table (CHARACTER VARYING, nullable)

the routine result’s SQL name, FUNCTION-typed by construction. With the two columns above this is the departing side of the pairing relation’s key

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition; the data field’s named type’s binding, demanded unambiguous

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name, the row the write committed and the re-read fetches. With the two columns above this is the arriving side of the pairing relation’s key

candidates (INTEGER, nullable)

how many departures this data field’s hop could leave from, this row being one of them; 1 where one mutation field produces the payload. Above 1 is two producing fields naming different routines, which the generator resolves by first-producer-wins without saying so, and which this column says

intent_class_member_element (view)

The class a member slot delivers: intent_declared_type_element read at the slot’s own owner, one row per slot. A reader standing on a slot asks what it delivers and does not care whether a record component or a bean accessor answered, which is a reader’s question and therefore a view rather than a second peel. Source-keyed like the slot relation it extends, a graph reaching it through store_graph_source. The peel rule, the container vocabulary and the omission consequences are all stated on intent_declared_type_element and hold here unchanged; what this view adds is which owner a slot resolves to, which is exactly the join a reader would otherwise write for itself. The bean arm carries one condition the record arm does not need. A slot carries its accessor’s name and not its descriptor, and the peel is keyed by descriptor, so this arm picks the accessor among same-named methods the way the slot rule picked it in the first place, by the absence of parameter rows. That is the same reading applied twice rather than a second rule, and it is what stops a getTitle(int) declared beside getTitle() from lending its return type to the title slot.

Columns
source_name (CHARACTER VARYING, nullable)

the owning class’s classpath entry, carried from intent_class_member_slot; the partition a graph reaches through store_graph_source

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class offering the slot

origin (CHARACTER VARYING, nullable)

RECORD_COMPONENT or BEAN_ACCESSOR, as on intent_class_member_slot; which arm produced the slot, and here also which owner kind the peel was read at

slot_name (CHARACTER VARYING, nullable)

the name an author writes into @field(name:), as on intent_class_member_slot; two spellings of one property are two slots and so two rows, which this view inherits rather than resolves

accessor_method_name (CHARACTER VARYING, nullable)

the Java declaration the slot resolves to, as on intent_class_member_slot

element_path (CHARACTER VARYING, nullable)

the position the peel stopped at, carried from intent_declared_type_element

element_class (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class the slot delivers, carried from intent_declared_type_element; not a foreign key, on the same terms

variance (CHARACTER VARYING, nullable)

NONE, EXTENDS or SUPER at the position landed on, carried from intent_declared_type_element

intent_class_member_slot (view)

The member names a class offers an SDL author, in the author’s vocabulary rather than the JVM’s: what @field(name:) resolves against on a type whose backing is a class rather than a table. Keyed by the census’s own key, not by a graph: the question is about a class, and a graph reaches it the way it reaches any source-keyed fact, through store_graph_source. A class takes exactly one arm, chosen by its declared form, which is what keeps a slot name unambiguous about where it came from: a record answers with its components, and anything else answers with its bean accessors. The bean rule is the reason this is a relation and not a reader’s loop. It was written in the LSP-facing projection, where it had to be re-run on every build to hand the same list back, and it is a rule over the census rather than a fact about any graph: a public no-argument method whose name is get or is followed by an upper-case letter offers the remainder with its first letter lowered. The two prefixes are joined as data rather than spelled twice, and no arm reads the return type: a method named isTitle returning a String is a slot exactly as the projection made it one, because an author who wrote that name meant that member and a rule that second-guessed the type would hide it. Taking no parameters is read as the absence of parameter rows rather than as a descriptor’s shape, which is the same reading and the one that does not depend on how a descriptor is spelled. Two spellings of one property (getTitle beside isTitle) are two rows, the same two the projection’s list held; a reader wanting one takes the first, and a reader offering candidates offers both. Declaration order is deliberately not carried: the census records a position for a record component and nothing for a method, so an ordered column would be a fact about one arm only, and a reader that wants a stable list orders by name. What this relation does not answer is which class a type is backed by. What a slot delivers is one relation further on (intent_class_member_element, the peel read at the slot’s own owner), the hop a coordinate takes over it is intent_field_accessor_hop, and the closure over those hops is intent_type_backing_class. A reader that already holds the class name asks this relation only what the class offers, which is the question it answers and the whole of it.

Columns
source_name (CHARACTER VARYING, nullable)

the owning class’s classpath entry, carried from jvm_class; the partition a graph reaches through store_graph_source, and the reason one workspace’s modules do not fold their classes into each other’s answers

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class offering the slot

origin (CHARACTER VARYING, nullable)

RECORD_COMPONENT or BEAN_ACCESSOR: which arm produced the row, and the whole of what a consumer needs to say what it found. A function of the class’s declared form rather than of the slot, so every slot of one class carries the same value, and carried per row anyway because the readers that fork on it (a diagnostic naming the member kind, a jump landing on a field rather than a method) hold a slot and not a class kind

slot_name (CHARACTER VARYING, nullable)

the name an author writes into @field(name:): a record component’s own name, or a bean accessor’s name with its prefix removed and its first letter lowered. Not unique within a class, two accessor spellings of one property being two rows

display_type (CHARACTER VARYING, nullable)

the member’s type as the source declared it, package-less and with type arguments kept (String, Integer, List<Film>); what a hover shows beside the name. The declared form rather than the erasure because this column exists to be rendered, and an author reading List learns less than one reading List<Film>. The erasure is a join away on the census relation the arm came from, for a reader comparing a type’s identity rather than showing it

accessor_method_name (CHARACTER VARYING, nullable)

the Java declaration the slot resolves to in source: the accessor method’s own name, which for a record component is the component name. The one column goto-definition reads, and the reason the bean rule’s two directions (a name to a slot, a slot back to its declaration) are stated once here rather than re-derived from slot_name by whoever needs the reverse

intent_column_match_claim (view)

The column-match structural classifier: a field whose name resolves against the table its site navigates to claims TABLE_COLUMN, no directive involved. Usually that is the parent’s own bound table, and where an authored @reference path moves the site it is the path’s terminal, which intent_field_column_scope answers for both and this view no longer decides for itself. One view per structural classifier, so the row’s columns are exactly this classifier’s join witnesses. The reading transcribes the classification walk’s fall-through arm: the field’s named type has kind SCALAR or ENUM, the site resolves against exactly one table (the resolution is intent_field_column_scope’s, which requires a single candidate on its parent-binding rule and so is how this arm transcribes the walk’s Ambiguous verdict; distinguishing that decline from a name not in the catalog at all is a future resolution-stratum detection over graphitron_table, not something this view’s absence encodes), and the effective name matches a column, generated-Java-name tier before SQL-name tier, both case-insensitive, collapsed to the first match in tier-then-ordinal order. The effective name is the @field binding where one decoded, else the field name; the arm needs no undecoded presence fallback because a declined @field decode leaves the COALESCE on the field name, which is the walk’s own fallback. The scope drives the join and that is load-bearing rather than stylistic: H2 re-evaluates a joined derived relation once per outer row, so reading the scope from underneath graphql_field costs the whole relation per candidate field and measured seventy times this shape on a store holding a dozen graphs. Any relation joining a derivation this deep wants the derivation first in the FROM clause. Deliberately mask-light: the only exclusion is the three root names, and it arrives through the scope view’s own binding read rather than being restated here, roots classifying before any table binding is read. The scope’s parent-binding rule is mask-light for the same reason, so a coordinate an authored directive claims still produces the structural reading here and the reduction is what drops it. No parent-kind gate and no directive knowledge: masking against authored claims is the reduction’s job, and the raw structural reading surviving here is what lets a diagnostic say "would classify as a table column; @service overrides it".

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_field

type_name (CHARACTER VARYING, nullable)

the claimed field’s owning type

field_name (CHARACTER VARYING, nullable)

the claimed field’s name within the owning type

classifier (CHARACTER VARYING, nullable)

always TABLE_COLUMN; stated as a column so claim views union at the classifier grain

matched_name (CHARACTER VARYING, nullable)

the effective name the classifier resolved: the @field binding where one decoded, else the field name. The classifier’s own product rather than a projection of either input, which is what earns it a column here

matched_by (CHARACTER VARYING, nullable)

which tier matched: JOOQ_NAME (the generated Java field name) or SQL_NAME. Makes the two-tier precedence visible data instead of a hidden pick

table_source_name (CHARACTER VARYING, nullable)

witness: the resolved table’s catalog partition, the first column of the sql_column key this row names

table_schema (CHARACTER VARYING, nullable)

witness: the resolved table’s SQL schema

table_name (CHARACTER VARYING, nullable)

witness: the resolved table’s SQL name

column_name (CHARACTER VARYING, nullable)

witness: the matched column’s SQL name. With the three columns above this is sql_column’s full key; the column’s other facts (its jOOQ name, type, nullability) are one join away, per the referenced-side discipline sql_referential_constraint states

source_name (CHARACTER VARYING, nullable)

the claimed field’s own declaration file; the position a diagnostic would carry

source_line (INTEGER, nullable)

source line of the field declaration, 1-based

source_column (INTEGER, nullable)

source column of the field declaration, 1-based

intent_condition_membership (view)

Which tables a coordinate contributes a WHERE clause against, one row per coordinate and table. The condition family’s membership fold: a consumer minting the generated filter glue reads this to know which glue exists, and every other relation in the family answers a question about a row this one admits. Membership is presence and nothing else, which is what makes it a fold rather than a payload: what the predicates are, which columns they compare and which arguments carry them are the resolution relations' answers, read through this one. The rule is that the coordinate’s lowered filter surface is nonempty, and it is nonempty when any of five sources contributes. Three are authored and cannot be suppressed, a @condition being a method the author wrote and asked to have called: one on the field itself, one on any argument of it whatever that argument’s role, and one on any input field the field’s arguments reach at any depth. Two are generated and can be: an argument whose role resolves a predicate, and an input field whose role does. The generated pair is where the modifiers matter, and they are read at the grain the classifier reads them at. An argument contributes only when its role is one that resolves a predicate, which is NODE_ID or NAME_MATCHED and not the four that resolve something else; ORDER_BY and PAGINATE are consumed by the ordering and pagination facts, and INPUT_EXPANSION contributes nothing of its own, the contribution being the fields below it, which arrive here as the input-field sources instead. An input field contributes under the same two roles, and additionally not when the override cascade suppresses it, which is intent_input_occurrence_override read at the occurrence rather than at the field, and not when a @lookupKey consumes it. That last exclusion propagates: a @lookupKey on the argument consumes the whole expansion beneath it, so an occurrence under such an argument contributes nothing at any depth, which is a rule about the argument applied at the grain of the field under it. Four kinds of coordinate are excluded outright because their filter surface is not a filter surface. A mutation’s predicates come from the write partition and not from here, and the write payload argument that would otherwise read as a filter is the largest part of what that exclusion removes. A @service field generates no SQL at all. The relay node field resolves a node and never filters, its shape carrying the node-resolve member and no condition member however its id argument classifies. And an argument consumed by a keyed lookup is the VALUES-and-join path rather than the WHERE clause. Each is stated as its own exclusion rather than folded into one predicate, because they are four different reasons and a reader debugging a missing row wants to know which one fired. The table side is intent_field_scope_table at its own grain, which is why that relation’s grain had to be corrected before this fold could exist: a @condition on a field with no arguments has a table to filter and no argument to carry it. A multi-table polymorphic root gets one row per branch here for free, that relation carrying a PARTICIPANT_TABLE row per participant table, and the branch fan-out is therefore the scope table’s and not this relation’s. Membership itself stays a property of the coordinate: a name that resolves a column on one participant and not on another is a build failure at that participant rather than a membership difference between branches, so the fold has nothing to decide there and deliberately does not fan the sources out. A consumer minting the per-participant glue method, whose name is the participant’s, joins intent_field_participant_scope_table on the table. Three populations are missing from this relation and each is measured rather than supposed. The store has no read-side refusal: a coordinate whose argument classification fails is refused whole and has no filter surface at all, and where the write partition states its refusals in two relations of their own the filter surface states none, so a refused coordinate has a row here that no consumer will find glue for. On a schema that builds, that population is empty, every refusal being a build failure; it is the fold’s one structural gap and closing it is a relation of its own. The other two are silences one rung up, both found by diffing this relation against what the producer emits for the example schema, and both filed: a field returning an author-declared connection type has no scope row, and an argument whose @reference path ends in a condition hop resolves no column, so six coordinates of that schema contribute nothing here that the generator does contribute. Absence otherwise is every coordinate that reads no table, every coordinate whose arguments all resolve to something other than a predicate, and every coordinate whose generated predicates are all suppressed while it carries no authored condition to fall back on.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the contributing source; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, nullable)

the type owning the filtering field

field_name (CHARACTER VARYING, nullable)

the field whose filter surface this row admits; with the type above and the table below, the grain, and the same key the condition command relation is keyed by

basis (CHARACTER VARYING, nullable)

which rule resolved the table, carried from intent_field_scope_table unchanged: NAMED_TYPE_TABLE, PAYLOAD_TABLE, MUTATION_TABLE or PARTICIPANT_TABLE. PARTICIPANT_TABLE is the one that changes what a consumer does with the row, marking it one branch of a polymorphic root rather than a coordinate’s whole statement, and so deciding which glue method name is minted; the other three are provenance

table_source_name (CHARACTER VARYING, nullable)

the filtered table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the filtered table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the filtered table’s SQL name; with the two columns above this is sql_table’s full key, so the table’s own columns are one join away

intent_connection_element_type (view)

Which type a connection type is a connection over: one row per OBJECT type whose shape is a Relay connection, naming the element the connection paginates. The shape test is structural and is the classifier’s own, transcribed rather than reinvented: the type declares a field named edges, that field’s named type is an OBJECT, and that object declares a field named node, whose named type is the element. Nothing about a directive is read, which is the point. A connection the generator synthesised from @asConnection and a connection the author wrote out in the SDL have the same shape and therefore the same row here, where every rule that read the synthesis record instead could see only the first. Field names being unique within a type, edges and node each resolve at most once, so this relation is one row per type and never fans out. The names are literal because the spec’s are: Relay fixes edges and node, and a type spelling them differently is not a connection to the classifier either. Absence is every type that is not a connection, which is nearly all of them, and also the two near misses worth naming so a reader does not mistake them for defects: a type with edges whose element declares no node, and a type with node reachable some other way than through edges. Neither is a connection under the spec and neither is one here. What this relation does not state is nullability or the page-info shape; a consumer needing the element’s optionality reads the node field’s own graphql_field row, which is one join from the element name this row carries. The consumer that matters is intent_field_navigated_type, which is where the element name becomes the type a field’s own SQL navigates as; reading this relation directly is asking the narrower question of what a type is, and a rule that wants to know what a field reaches should read that one.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the connection type’s own row; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, nullable)

the connection type itself, the wrapper a field returns; with the graph, the grain

element_type_name (CHARACTER VARYING, nullable)

the type the connection paginates, read off the edge type’s node field’s named type with its wrappers already stripped by graphql_field. A name and not a binding: whether the element is bound to a table is intent_resolved_type_binding’s answer and deliberately not asked here

intent_connection_facet (view)

Which facets one connection carrier surfaces, and in which order: one row per @asFacet application reachable from the carrier’s own filter arguments. The use-keyed half of the facet reading, and what a consumer emitting a faceted connection reads. The carrier population is the expansion rather than the directive. graphitron_field_synthesis holds a row exactly where the CONNECTION macro rewrote a field’s type expression, which is @asConnection on a bare list with a named element and nothing else, so @asConnection that expanded nothing carries no facets here and neither does a structural Connection return type, whose shape is the author’s and which the promoter appends no facets field to. That is the spec’s "inert at the others" reading, held by construction rather than by an arm. Reachability is one hop: the facet field is declared on a type an argument of the carrier names, which is the promoter’s own walk and not a transitive closure through nested input objects. position is dense per carrier and is the emission order, argument declaration order then facet field declaration order, which is what lets a consumer fold these rows into a file and get the same bytes twice. A facet name repeated across one carrier’s filter inputs collapses to its first occurrence, transcribing the promoter’s first-wins dedup; that is a backstop and not a rule, a duplicate being rejected with a named diagnostic before it can reach an accepted schema, and it sits after the definition-keyed gate so a malformed duplicate never consumes the name a well-formed one would take. Two carriers sharing one connection name each read their own filter arguments here rather than one reconciled registry entry, which agrees with that registry on every schema that assembles: carriers minting one connection name must project the same facets, and a disagreement is a rejection naming both. What this relation does not state is whether the emitter serves the carrier it resolves. That a faceted carrier must be a root Query connection over a table-backed element is a limit of the emitter that exists today, enforced as a rejection, and putting it here would make an emitter’s reach a fact about the schema.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the carrier’s arguments

type_name (CHARACTER VARYING, nullable)

the type owning the carrier field

field_name (CHARACTER VARYING, nullable)

the carrier field’s name within that type; with the column above, the connection carrier’s coordinate

position (BIGINT, nullable)

the facet’s place in this carrier’s facet list, 1-based and dense: argument declaration order, then facet field declaration order. The emission order, so a consumer reads it rather than re-deriving it from the two ordinals it was computed from

filter_argument_name (CHARACTER VARYING, nullable)

the carrier argument the facet’s binding rides in. Half of a facet’s suppression identity at emission: a same-named field on a sibling filter argument is a different binding, and the pair with facet_field_name is what tells them apart

facet_type_name (CHARACTER VARYING, nullable)

witness: the input object type the application was written on, which is the argument’s named type. With the column beside it this is intent_facet_binding’s key, so the application’s own position is one join away

facet_field_name (CHARACTER VARYING, nullable)

the facet field’s name: the label the counts surface under, and the other half of the suppression identity

column_name (CHARACTER VARYING, nullable)

the column the counts group by, carried from intent_facet_binding

value_type_name (CHARACTER VARYING, nullable)

the named type a facet key carries, carried from intent_facet_binding

value_nullable (BOOLEAN, nullable)

whether a facet key may be null, carried from intent_facet_binding

source_name (CHARACTER VARYING, nullable)

the @asFacet application’s own file, carried from intent_facet_binding: a diagnostic about a facet points at the application and not at the carrier that consumes it

source_line (INTEGER, nullable)

source line of the application, 1-based

source_column (INTEGER, nullable)

source column of the application, 1-based

intent_declared_type_element (view)

The class a declared type delivers: the type with its delivery wrappers peeled off, one row per owner. A member declared as a List of Film delivers Film, and so do a CompletableFuture of a List of Film and a Map from a key to Film, which is the rule that lets an SDL field naming one object stand on a member, or on a producer method, that hands back many. Keyed by the declared type’s own owner rather than by any reader’s subject, which is the correction a second reader forced: the rule was first stated over member slots, and a producer method’s return is the same declared form under a key no slot relation can hold, so a peel keyed at either reader would have been spelled twice and drifted. A third reader arrived for the parameter arm and needed nothing changed here but the key, which is the shape paying for itself. The peel descends from the root position: at a position naming a container it steps to that container’s element argument, and it stops at the first position naming no container, or naming one whose element argument names no class. That stopping position is the row, and the descent is four outer joins deep rather than a recursion. The bound is deliberate and was measured into existence. A recursive form terminates on its own, a declared type being a finite tree, so termination was never the question; the cost was. H2 re-evaluates a recursive view once per outer row of whatever joins it, and the readers here join it without a class predicate on purpose, the accessor hop being total over standing classes, so at sixteen thousand census methods the hop took six minutes to return nothing where reading the peel by itself took a third of a second. Four is what the reflective walk this replaces also descends, so the bound costs no agreement with it, and a nesting deeper than four delivers the last container reached rather than silently delivering the wrong class: element_path shows the depth and element_class names a container, which is a shape a reader can detect and a detection can be built on. The containers are intent_delivery_container’s rows, joined once per level, which is why they are a relation rather than a list inlined in this one. The recursion is not the one the SDL type graph needs a guard for. A declared type is a finite tree, so the descent terminates on its own, and the depth is the type’s rather than a bound the rule picks. Two populations fall away with no filter, because the census already omits them: a primitive-typed owner and an array-typed owner name no class at their root and so have no spine at all, an array’s component being the next step down and this walk never taking that step. What this view does not do is judge the class it lands on. A raw List with no type argument delivers java.util.List and says so, and an owner delivering java.lang.String is a row like any other; which landing classes are worth binding an SDL type to is a filter a reader applies rather than a fact this relation withholds.

Columns
source_name (CHARACTER VARYING, nullable)

the owning class’s classpath entry, carried from intent_declared_type_ref; the partition a graph reaches through store_graph_source

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class declaring the owner

owner_kind (CHARACTER VARYING, nullable)

METHOD_RETURN or RECORD_COMPONENT, as on intent_declared_type_ref

owner_name (CHARACTER VARYING, nullable)

the owner’s own name, as on intent_declared_type_ref

owner_descriptor (CHARACTER VARYING, nullable)

the owning method’s raw JVM descriptor, NULL exactly on the record arm, as on intent_declared_type_ref; the column a reader carries back to the census method it resolved

owner_position (INTEGER, nullable)

the parameter’s 0-based position, NULL exactly on the other two arms, as on intent_declared_type_ref; what tells one parameter’s peel from its neighbour’s under a key they otherwise share

element_path (CHARACTER VARYING, nullable)

the position the peel stopped at, the empty string where the declared type names its own delivery. The evidence for the answer rather than decoration: a reader can see whether a row came off the root or off three descents, and a test can pin which without asserting on the class that happened to be there

element_class (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class the owner delivers. Not a foreign key, on jvm_method_return_type_ref.referenced_class’s terms, so an owner delivering a class no classpath entry declares is an ordinary row and a reader learns nothing further about it

variance (CHARACTER VARYING, nullable)

NONE, EXTENDS or SUPER at the position landed on: a type declared as a List of ? extends Film delivers Film under EXTENDS. Carried because the three declare different things about which direction values flow and the class name alone cannot tell them apart

delivers_many (BOOLEAN, nullable)

whether the declared type delivers many of the element rather than one: TRUE where the descent crossed a container that multiplies, FALSE where it crossed only wrappers or did not descend at all. Carried rather than left to the reader because element_path says how deep the descent went and not what it went through, so recovering this would mean re-reading the positions and the container vocabulary that this view already read. A raw container is FALSE and delivers itself, the descent never having happened, which is the same reading the reflective walk reaches by requiring a parameterised type before it looks at all.

intent_declared_type_ref (view)

Every declared type in the census that a reader can peel, keyed by the owner the census gives it: one row per position, unioning the method-return and record-component type-reference relations. This is the union jvm_record_component_type_ref’s own comment forecast, and the owner key is the reason it is stated here rather than at a reader: the three census relations are three keys, so a reader whose question is uniform across the owners has to name the owner before it can ask, and naming it once means the two readers that peel a declared type ask the same relation. Source-keyed like the census, a graph reaching it through store_graph_source. The path grammar and the omission rules are jvm_method_return_type_ref’s and hold unchanged: the empty path is the type itself, a digit is a 0-based type-argument index, and a position naming no class has no row, so a primitive-typed member and an array-typed member alike name nothing at their root. The parameter relation is the third arm and joined when a reader arrived that peels a parameter, which is the widening this view was shaped to take rather than a second view: it brought owner_position with it, NULL on the two arms whose owner needs no ordinal. Two of the three key parts are therefore arm-determined, and neither NULL is a fact withheld; owner_kind says which parts to read, and a reader that joins the owner key blind uses IS NOT DISTINCT FROM, as the peel above this one does.

Columns
source_name (CHARACTER VARYING, nullable)

the owning class’s classpath entry, as on jvm_class; the partition a graph reaches through store_graph_source

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class declaring the owner

owner_kind (CHARACTER VARYING, nullable)

METHOD_RETURN, RECORD_COMPONENT or METHOD_PARAMETER: which census relation the position was read from, and the whole of what says how to read the three columns beside it. A closed vocabulary, one value per census relation of this shape, and there is no fourth

owner_name (CHARACTER VARYING, nullable)

the owner’s own name: a method name on the return and parameter arms, a component name on the record arm. Never a key on its own, overloads sharing a method name and a parameter sharing its method’s. A parameter’s own name is not here and could not be, being NULL for a consumer compiled without -parameters, so the ordinal is the identity

owner_descriptor (CHARACTER VARYING, nullable)

the owning method’s raw JVM descriptor, the overload discriminator on the return and parameter arms; NULL exactly on the record arm, where a component is named on its own and there is no descriptor to carry. A NULL determined entirely by owner_kind, which is the two-arm union’s key shape rather than a fact withheld, on intent_authored_claim_conflict.field_name’s terms

owner_position (INTEGER, nullable)

the parameter’s 0-based position, completing the key on the parameter arm; NULL exactly on the other two, whose owner is identified without an ordinal. Determined entirely by owner_kind, the three-arm union’s key shape rather than a fact withheld, on owner_descriptor’s terms

type_path (CHARACTER VARYING, nullable)

the position within the declared type; the grammar is stated on jvm_method_return_type_ref.type_path

referenced_class (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class named at this position; the omission rules are stated on jvm_method_return_type_ref.referenced_class

variance (CHARACTER VARYING, nullable)

NONE, EXTENDS or SUPER, as on jvm_method_return_type_ref.variance

intent_delivery_container (view)

The classes a declared type delivers something through rather than delivers: the container vocabulary the peel descends, one row per class with the type-argument position its element sits at. Named data rather than a predicate spelled inside its reader, on the terms intent_class_member_slot joins its two bean prefixes, and its own relation because the peel reads it twice, once to descend and once to ask whether a position can descend at all. A rule that decides which classes are containers is exactly the kind that must have one home. They are named rather than recognised through a closure over the declared supertype relation because such a closure cannot answer here: nothing ships the JDK as a classpath entry, so java.util.List declares nothing the census holds and standing in for it is unreachable from below. The set is closed by what a generator meets rather than by what Java offers, so a consumer returning its own collection type is not a container here and delivers itself; widening it is adding a row.

Columns
container_class (CHARACTER VARYING, nullable)

the fully-qualified binary name of the container class, spelled as the census spells a class name

element_index (CHARACTER VARYING, nullable)

the 0-based type-argument position the delivered element sits at, as a type_path step: 0 for the single-argument containers, 1 for a map, whose key is not what it delivers

multiplies (BOOLEAN, nullable)

whether passing through this container makes the delivery many rather than one. A collection multiplies and a wrapper does not, which is why the two live in one relation rather than two: both are stepped through by the same descent, and only what the step means to cardinality differs. A map is the case worth stating, and it is FALSE: a map from a key to one value delivers one, and a map from a key to a list delivers many because of the list, so the map itself is transparent and the descent through it decides nothing.

intent_errors_field

Which field of a type is an error channel: a nullable list of a polymorphic type whose every member carries @error. One row per such field, total over them, and a field’s shape alone decides it, so this says nothing about whether any producer routes errors into it; a type nobody returns has its errors field named here exactly as a payload’s does. That is deliberate and it is what lets the relation be shaped by the field rather than by the producer, which is the difference between stating a fact and stating one reader’s question. The shape is four conditions and every one of them is the walk’s own. The list must be nullable because a non-null list would raise a non-nullable-field error on the success arm, where the channel resolves to no list at all, and take the sibling data field down with it. The named type must be a union or an interface, a single @error type not being a channel: the dispatch table the channel drives is a choice among mapped types and there is nothing to choose. Every member must carry @error, one that does not making the container a mixed result type rather than an error list. And an @asConnection field is excluded, its wrapper being a Connection rather than a list, so the shape it presents to a channel reader is not the one it presents to graphql-java. The container’s members in their order are intent_errors_field_member, a child rather than a column here because a list is rows; the count of them is that relation’s to answer and not a number stored beside its own rows. This was the errors_field CTE inside intent_carrier_data_field, promoted on the second reader: the carrier scan asks which of a payload’s fields are not data channels and the error channel asks which one is the channel, and two readings of one shape is where a fact model puts a relation. Where a payload declares more than one errors-shaped field the walk takes the first in declaration order; this relation names all of them and carries the ordinal that decides, the picking being intent_field_error_channel’s. Materialized: this relation is a table refilled from intent_errors_field_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, nullable)

the type declaring the field; a payload or carrier where a producer routes into it, and any type at all where none does

field_name (CHARACTER VARYING, nullable)

the errors channel’s field name within its type; the coordinate an author’s cursor sits on

ordinal (INTEGER, nullable)

the field’s declaration index within its type, carried from graphql_field. Two readings ride it: it is the SDL order that decides which errors-shaped field a payload declaring several routes through, and on the payload-class arm it is also the canonical constructor’s parameter index, records preserving declaration order and hand-rolled payload classes being expected to match it

container_name (CHARACTER VARYING, nullable)

the union or interface the field’s element type names; the container whose members are the mapped @error types

container_kind (CHARACTER VARYING, nullable)

which polymorphic form the container is, a closed two-value domain: UNION, INTERFACE. Carried so a reader need not re-read graphql_type to know which arm of intent_poly_member supplied the members

intent_errors_field_live (view)

This states the rule and is evaluated on demand. The canonical name intent_errors_field beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_errors_field.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_errors_field.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_errors_field.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_errors_field.field_name, whose comment carries what the value means

ordinal (INTEGER, nullable)

the ordinal of a row of this rule, materialized into intent_errors_field.ordinal, whose comment carries what the value means

container_name (CHARACTER VARYING, nullable)

the container_name of a row of this rule, materialized into intent_errors_field.container_name, whose comment carries what the value means

container_kind (CHARACTER VARYING, nullable)

the container_kind of a row of this rule, materialized into intent_errors_field.container_kind, whose comment carries what the value means

intent_errors_field_member (view)

The @error types one error channel maps, in order: the ordered child of intent_errors_field, one row per member of the field’s container. Every member carries @error, that being a condition of the parent relation admitting the field at all, so this relation needs no error predicate of its own and a row here is always a mapped type. Ordered because the consumers are ordered: the dispatch table is tried in this order, and the fingerprint that disambiguates two channels sharing a constant name is a digest over the flattened handler list in this order, so a re-ordering is a different emitted name and not a cosmetic difference. A child relation rather than a column on the parent because a list is rows; a column holding a serialized member set would answer set equality and nothing else, which is the reading intent_type_backing_conflict declines for the same reason. Keyed by the errors field and not by the container, so two fields naming one union are two ordered lists rather than one shared by reference: that costs rows and buys a reader the ability to join on its own coordinate without knowing the container, and the container is a column on the parent for the reader that would rather group. The handlers each of these types declares are graphitron_error_handler’s, keyed by the type alone, an @error type’s handler list being the type’s property and not this channel’s.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the errors field

type_name (CHARACTER VARYING, nullable)

the type declaring the errors field, carried from intent_errors_field

field_name (CHARACTER VARYING, nullable)

the errors field these members are the mapped types of

position (INTEGER, nullable)

source order within the container, carried from intent_poly_member; authored on a union and derived from declaration sites on an interface, which that relation states the consequence of

error_type_name (CHARACTER VARYING, nullable)

the @error type at this position; always a captured type carrying @error, the parent relation admitting no field whose container holds anything else

intent_facet_binding (view)

What one @asFacet application binds, at the applications that are well formed: the column its counts group by, the named type those counts are keyed on, and whether such a key may be null. The definition-keyed half of the facet reading, keyed on the input field the directive sits on and resolving nothing about who consumes it; intent_connection_facet is the use-keyed half and reads this one. The split is the resolver’s own rather than a convenience: the classifier states this predicate in one place precisely because the synthesis walk that gates on it sees a field and no consuming coordinate, and every check that needs one lives away from it. The arms transcribe that predicate. The field carries a @field(name:) binding, because a facet value is a GROUP BY key on one column and nothing else names which. It is optional, because a non-null filter is always active, so its facet could never show the counts the filter is not narrowing. Its named type is not an input object, for the same one-column reason, and is not ID, ID being where a node-id reading arises with no directive to point at. It carries no @reference, @condition or @nodeId, those being the join-mediated and node-id bindings the direct-column facet emitter does not serve. The owning type is an INPUT_OBJECT, which is the predicate’s domain and not a further arm: @asFacet written anywhere else is a use-keyed misuse and declines here by never meeting a filter input. Every one of those declines is a misuse the build rejects with a named diagnostic, so on a schema that assembles at all this relation holds every @asFacet application in the graph, and absence is a defect relation’s subject rather than this one’s. value_nullable reads the list element where the filter field is a list and the field itself where it is not, the non-null form having already declined, which is the promoter’s own unwrapping and not a restatement of it. The synthesized FacetValue type name those two columns decide is deliberately not a column here: it is a naming convention over them, and the naming belongs where the other minted names are formed. Deliberately not registered, on measurement rather than on size: registering it costs its one reader more than it saves. Inlined, this rule lets that reader drive from the carrier’s own arguments and reach the facets of each by key, which measured linear in the applications. As a table it is the driving relation instead, and the reader’s join to graphql_argument on named_type has no index to seek, so it degrades to every argument of the graph once per row here: on a fixture of 144 applications the reader went from 659 scans to 7779, and an index on this relation’s own coordinate moved neither figure, the missing seek being on the other side of that join.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_facet

type_name (CHARACTER VARYING, nullable)

the input object type the facet field is declared on

field_name (CHARACTER VARYING, nullable)

the facet field’s name within that input type; with the two columns above, the grain

ordinal (INTEGER, nullable)

the field’s declaration order within its input type, carried from graphql_field; the inner half of the order one carrier’s facets surface in

column_name (CHARACTER VARYING, nullable)

the @field(name:) binding as written: the column the counts group by. Which table it resolves on is the consuming carrier’s element binding and not a fact about the application, so it is not here

value_type_name (CHARACTER VARYING, nullable)

the named type a facet key carries, the filter field’s leaf; a scalar or an enum, an input object being a decline above

value_nullable (BOOLEAN, nullable)

whether a facet key may be null: the list element’s nullability where the filter field is a list, TRUE otherwise. With value_type_name it decides both the synthesized FacetValue type the counts surface through and whether the aggregate scrubs a null key

source_name (CHARACTER VARYING, nullable)

the @asFacet application’s own file; the position a diagnostic would carry

source_line (INTEGER, nullable)

source line of the application, 1-based

source_column (INTEGER, nullable)

source column of the application, 1-based

intent_federation_key (view)

Every @key a graph’s emitted schema carries, authored and synthesized alike: the composition two readers already ask for, the round trip that re-emits the applications and the agreement anchor that pins the derivation against the pipeline’s registry rewrite. A relation rather than a union each of them assembles for itself, on the rule that a composition with a second asker is a relation. The grain is the authored relation’s, with a NULL ordinal on the synthesized arm rather than an invented one: document order is a property of something the author wrote, and a derived row has no position in a document. UNION ALL and not UNION, deliberately. The authored arm is unique on its own key already and the synthesized arm cannot collide with it, its condition being that no authored id key exists, so deduplication could only ever fold together rows a reader wants told apart: two authored @key(fields: "id") applications at distinct ordinals are two rows here, which is the arity the authored relation states and this reduction owes its readers. Key grain only. The path and segment children stay authored-only until a reader asks for them composed, the synthesized arm’s single id path being recoverable from fields_sdl by the same rule that would have decoded it. A reader wanting a total order over both arms orders the authored rows by ordinal and appends the derived one, which is the ordering the composing query owns rather than one this relation invents.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from whichever arm produced the row

type_name (CHARACTER VARYING, nullable)

the type the key sits on

ordinal (INTEGER, nullable)

the authored application’s position in document order; NULL on a synthesized row, which is the stated absent bucket rather than a missing value, a derived row having no document position and the type’s declaration site being one join away

fields_sdl (CHARACTER VARYING, nullable)

the field-set literal: as written on an authored row, and the rule’s own id on a synthesized one

resolvable (BOOLEAN, nullable)

as written on an authored row, NULL where the author omitted it; always true on a synthesized one

intent_field_accessor_hop (view)

Where an accessor hop lands: for a field coordinate and a class its parent might stand on, the class the member reading that field delivers. One edge of the walk that binds SDL types to backing classes, stated as a fact instead of as a step, so the closure over these edges is a reader’s recursion rather than a rule buried inside one. The slot a coordinate reads is the @field(name:) override where the field carries one and the field’s own name otherwise, which is the resolution the emission side makes; an output field and an input-object field resolve it identically and are one population here, that directive landing on both. Total over standing classes by construction. Nothing here says which class a parent actually stands on, so a coordinate pairs with every class in the graph’s sources offering a slot of that name, and a row is a conditional rather than an answer. That totality is what makes this an edge relation instead of another copy of the binding, and it is why this is a view that is never materialized: the product is large wherever a slot name is common and small wherever a reader binds the standing class before asking. Ambiguity is rows and no count. Two spellings of one property are two slots on intent_class_member_slot’s stated terms, and that relation already declines to choose between them, so a count here would be a second stance on a question one relation has settled. Two departures from the walk this replaces, both to be adjudicated against its shadow rather than assumed harmless. The first is that an SDL field’s arguments are not read at all. The walk probes for an accessor whose parameters match them, and a slot is a no-argument member by definition, so this relation hops where the walk would not (an argument-taking field standing on a no-argument accessor of the same name) and stays silent where the walk would hop (a field whose accessor takes those arguments). Reading the shape here would mean a slot relation holding parameterised members, which is a different question from the one that relation answers, so the difference is recorded rather than quietly closed. The second is that the walk skips a field carrying @service and skips a child type already bound; both are conditions on the closure rather than properties of an edge, and neither belongs here.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_field

type_name (CHARACTER VARYING, nullable)

the coordinate’s owning type: the type whose standing class the hop departs from

field_name (CHARACTER VARYING, nullable)

the coordinate’s field name within that type

source_name (CHARACTER VARYING, nullable)

the departing class’s classpath entry, as on jvm_class; the census partition the graph reached through store_graph_source, and the reason another graph’s entries offer no hops here

from_class_name (CHARACTER VARYING, nullable)

the class the parent must stand on for this row to hold. A hypothesis the row is conditional on rather than a fact about the coordinate, which is exactly what keeps this relation clear of the closure that decides it

origin (CHARACTER VARYING, nullable)

RECORD_COMPONENT or BEAN_ACCESSOR, as on intent_class_member_slot

slot_name (CHARACTER VARYING, nullable)

the member name the coordinate resolved to: the @field(name:) override, or the field’s own name where it carries none

accessor_method_name (CHARACTER VARYING, nullable)

the Java declaration the hop reads, as on intent_class_member_slot; the column a jump to the member’s own source lands on

to_class_name (CHARACTER VARYING, nullable)

the class the hop lands on: what the slot delivers with its wrappers peeled, on intent_class_member_element’s terms. Not a foreign key, a landing class no classpath entry declares being ordinary rather than exceptional

element_path (CHARACTER VARYING, nullable)

the position within the slot’s declared type the landing class was read at, carried from intent_class_member_element; what says whether the hop peeled anything

variance (CHARACTER VARYING, nullable)

NONE, EXTENDS or SUPER at that position, carried from intent_class_member_element

intent_field_chain_node (view)

Where a field’s @routine chain stands after each step, and how it got there. The chain is the field’s @routine and @reference applications walked as one running source; this relation is every place along it, and the one recursion in the family. A node at seq 0 is the routine’s own result, which intent_field_chain_start resolved; a node at seq k is where the k-th @reference path element written after that application lands, each departing from the previous node’s arrival through intent_field_reference_step_hop, exactly as intent_field_reference_step_target walks a path from a type’s binding. The hop relation’s name-matched arm is what carries the first element out of the function result, no foreign key being able to. Which elements are the chain’s is a comparison of source positions and not of ordinals, because @routine and @reference number their ordinals separately; the start carries the position that comparison is made against, so the rule that picks the last routine application is stated once, there. An element written before the routine is not in the tail at all, moving where the chain starts and never where it ends. Absence means "not reached", as on the target view: an element resolving to nothing ends the walk, so a chain whose second element is fine but whose first names an unknown key contributes only its seq 0 node, never a node standing where the walk did not arrive. last_seq is what makes that legible without a second relation, being the tail’s own extent rather than the walk’s: a walk that stalled has no row at last_seq and therefore no terminus, and a reader wanting to say where it stalled compares the two. The route into each node travels with it, which is the difference between this relation and the landing relation over it. A reader that has to render the chain’s joins needs the constraint and its orientation at every step, and before this relation those columns were computed inside a walk and then dropped, so a reader needing them had no choice but to write the walk again. Two vocabularies, kept apart on purpose: via says which directive put the chain here, in intent_field_chain_terminus’s own words, and step_via says which arm of the element’s resolution moved it, in intent_field_reference_step_hop’s. One relation carrying both under one name would make every reader say which it meant.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the chain’s start

type_name (CHARACTER VARYING, nullable)

the type owning the field the chain is written on

field_name (CHARACTER VARYING, nullable)

the field the chain is written on

seq (INTEGER, nullable)

the node’s 0-based position along the chain: 0 is the routine’s own result, k is where the k-th path element after it lands. Dense from 0 up to wherever the walk reached, which is not necessarily last_seq

last_seq (INTEGER, nullable)

the greatest seq the chain’s written elements would reach, carried on every node so the last one is identified without naming the tail again. The tail’s extent and not the walk’s, which is the whole of its use: seq = last_seq is the terminus, and seq < last_seq on every node of a chain whose walk stopped early says both that it stopped and where

ordinal (INTEGER, nullable)

the application’s ordinal within its own directive name: the @routine’s at seq 0, the owning @reference’s after that. A seq 0 node joins back to graphitron_routine on it and a later one to graphitron_field_reference

position (INTEGER, nullable)

the path element’s 0-based position within its own @reference application; NULL at seq 0, a routine application having no elements. Distinct from seq, which runs across applications

via (CHARACTER VARYING, nullable)

which directive put the chain at this node: ROUTINE at seq 0, REFERENCE after it. The vocabulary intent_field_chain_terminus publishes, projected from here unchanged

step_via (CHARACTER VARYING, nullable)

which arm of the element’s resolution moved the chain into this node: KEY, TABLE or NAME_MATCH, carried from intent_field_reference_step_hop where each is argued. NULL at seq 0, where no element moved it

key_matched_by (CHARACTER VARYING, nullable)

for a KEY step, which namespace answered: SQL_NAME or JOOQ_NAME. NULL on a TABLE or NAME_MATCH step and at seq 0, as on the hop relation

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition: the previous node’s arrival. NULL at seq 0, which the chain departs nothing to reach

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema; NULL at seq 0

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name; NULL at seq 0

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key; the function result itself at seq 0

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name. With the two columns above this is sql_table’s full key, so the node’s columns, its primary key and its generated classes are each one join away

table_type (CHARACTER VARYING, nullable)

the arriving table’s kind, carried from sql_table: FUNCTION at seq 0 by construction, and whatever the hopped-to table declares after that. The column the read-surface axes over a chain turn on, because a function result has no primary key and no foreign keys, so an ordering there cannot fall back on a key and must be authored

constraint_name (CHARACTER VARYING, nullable)

the foreign key the step joins on, named or discovered; NULL on a NAME_MATCH step and at seq 0. As on the hop relation, its own sql_referential_constraint key is this name under whichever endpoint declares it, which fk_on_from says

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key, FALSE when the arriving one does; the step’s direction. NULL on a NAME_MATCH step and at seq 0, as on the hop relation

targets (INTEGER, nullable)

how many distinct tables the chain reaches at this seq, this row’s arrival being one of them; 1 where the destination is certain. Separate from candidates for intent_field_reference_step_target.targets' reason: a step with three foreign keys connecting the two tables reaches one table by three routes, so a reader that only needs the destination can trust it while a reader that has to render the join cannot

candidates (INTEGER, nullable)

how many rows the chain resolved to at this seq, counting routes and not just destinations; 1 is the walk’s requirement for an expressible step, and a larger number is what the "which foreign key did you mean" rejection counts. At seq 0 it counts landings of the routine’s own name, two schemas declaring it being genuinely two

intent_field_chain_start (view)

Where a field’s @routine chain begins: the last @routine application written on the field, resolved to the table-valued function result it names. The last and not the first, because a second @routine application restarts the chain rather than extending it, so the chain a reader cares about departs from the last one; applications before it move where the chain starts and never where it ends. Two conditions, and both are the resolution rather than the rule: the spelling resolves through intent_spelled_table as any written table name does, and the result is then required to be FUNCTION-typed, which is the only kind @routine accepts. A routine name resolving to no FUNCTION-typed table yields no row, and the chain over it therefore has no start, no nodes and no terminus, which is the silence intent_field_chain_node states the general form of. Its own relation because three things need it and each needs a different part: intent_field_chain_node seeds its walk from the landing, that view’s tail is the elements written after this application’s source position, and a rejection about an unresolvable @routine names this coordinate. The source position travels with the row for the second of those. It is a position in a document and not an ordinal comparison, because @routine and @reference number their ordinals separately, the rule graphitron_field_reference’s own comment states. No arity column: two schemas declaring the routine’s name is genuinely two rows here, and the count a reader wants is over the chain’s landings rather than its departures, which is intent_field_chain_terminus.candidates. Adding one would put a second window function under a relation the node walk inlines, and buy a number nothing asks this relation for.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_routine

type_name (CHARACTER VARYING, nullable)

the type owning the field the chain is written on

field_name (CHARACTER VARYING, nullable)

the field the chain is written on

ordinal (INTEGER, nullable)

the @routine application’s own ordinal, which is the greatest on the field; joins back to graphitron_routine on it, and is the coordinate a rejection about the routine names

source_name (CHARACTER VARYING, nullable)

the schema document the application is written in, carried from graphitron_routine; the tail is measured within this document and not across documents

source_line (INTEGER, nullable)

the application’s line in that document

source_column (INTEGER, nullable)

the application’s column on that line. With the line and the document name, what an @reference application is compared against to decide whether it extends this chain or precedes it

table_source_name (CHARACTER VARYING, nullable)

the function result’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the function result’s SQL schema

table_name (CHARACTER VARYING, nullable)

the function result’s SQL name. With the two columns above this is sql_table’s full key, so the result’s columns and its generated classes are each one join away. Its table_type is FUNCTION by construction and is therefore not carried; the node relation states the kind of every landing including this one, so a reader asks one column whichever node it holds

intent_field_chain_terminus (view)

Where a field’s @routine chain lands, and what kind of table it lands on. The chain is the field’s @routine and @reference applications walked as one running source, and its terminus is the last node; every read-surface axis on a routine-backed field is a question about that node. Which table an ordering or a filter resolves its column names against is the terminus, and whether the terminus is a table-valued function’s result decides whether an ordering can fall back on a primary key at all, a function result having none. Both were answered per axis before this relation, each from the directives directly, which is how one property of one catalog object came to be restated as several unrelated refusals. Population: fields carrying at least one @routine. A field whose navigation is @reference alone has a terminus too and it is not this relation’s, intent_field_column_scope’s PATH_TERMINAL rule answering it from the type’s own binding; the chain arm that view is missing should read the chain relations rather than grow a second copy of the walk. A selection and not a walk: intent_field_chain_node carries every place the chain stands, and the terminus is its rows at seq = last_seq. That extent is the written tail’s and not the walk’s, so a chain whose walk stopped short has no row here at all, which is the same silence this relation always kept and the reason absence means "not reached", never "resolves to nothing in particular"; where such a walk stopped is now answerable on the node relation, by comparing the two. Ambiguity is rows, and they are landings rather than routes: an element reaching one table by three foreign keys is one row here where the node relation has three, a terminus being a place and not a join, and a reader that has to render the join reads the node relation where the routes are. Two schemas declaring the routine’s name is genuinely two landings, and candidates says so.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_routine

type_name (CHARACTER VARYING, nullable)

the type owning the field the chain is written on

field_name (CHARACTER VARYING, nullable)

the field the chain is written on

via (CHARACTER VARYING, nullable)

which node ends the chain: ROUTINE where the @routine application is the last one written, REFERENCE where a path element after it is. A property of the chain rather than of the landing, and what tells a reader whether the terminus is the function result itself or a table hopped to out of it; what kind of table it is is table_type beside it

ordinal (INTEGER, nullable)

the terminating application’s ordinal within its own directive name, so a ROUTINE row joins back to graphitron_routine on it and a REFERENCE row to graphitron_field_reference. The coordinate a rejection about the terminus names

position (INTEGER, nullable)

the terminating path element’s 0-based position within its application; NULL on a ROUTINE terminus, a routine application having no elements

table_source_name (CHARACTER VARYING, nullable)

the landing table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the landing table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the landing table’s SQL name. With the two columns above this is sql_table’s full key, so the terminus’s columns, its primary key and its generated classes are each one join away

table_type (CHARACTER VARYING, nullable)

the landing’s kind, carried from sql_table: FUNCTION where the chain ends on the routine’s own result, whatever the hopped-to table declares otherwise. The column every axis over this relation actually turns on, because a function result has no primary key and no foreign keys, so an ordering there cannot fall back on a key and must be authored. Always FUNCTION on a ROUTINE row, which is worth carrying rather than leaving to the via column: a reader asks one column whichever arm answered, and the day a non-function callable reaches a chain the answer changes here instead of at every reader

candidates (INTEGER, nullable)

how many distinct tables this field’s chain lands on, this row’s landing being one of them; 1 where the terminus is certain. Distinct landings and not routes, which is the arity a reader of a terminus needs and the reason this relation counts differently from the hop and target views; stated as a column rather than left to each reader’s own count, on intent_bound_table.candidates' terms

intent_field_column_scope

Which table the column names written at a field’s site resolve against: the field’s own navigation, answered at every site where a column name resolves at all. A row means "resolve names against this table"; absence means no column name resolves here, which is what a field of an unbound parent and a field whose authored path reaches no single table both get. The relation exists because two consumers were deriving the same navigation apart from each other. The structural column-match classifier read the parent’s binding directly, so a name at a site an authored path had moved still resolved against the parent, and intent_field_column_table restated the same two navigation rules to answer the narrower question of when the resolved table is not the parent’s own. Both read this now, so the navigation is derived once and the consumers differ only in what each adds to it. Three rules, and they are disjoint rather than ranked, which is what lets this relation be a plain union with no windowed collapse over it. A collapse would be a cost multiplier and not a small one: the column-match classifier joins this view per coordinate, and a window inside it forces the whole relation to materialize on every read, over a store that holds every graph of a workspace. Disjointness carries the one-row-per-site property instead, so state the rules with their boundaries. An authored @reference path resolves to its terminal element’s table: the first application’s last element, the repeatable directive’s ordinal grain collapsed the way the authored-claim view collapses @routine’s, demanding the terminal reach exactly one table rather than exactly one row, so an element joining two tables by three keys still names its destination. An element that resolved to several rows all reaching one table is one row here, the arm taking DISTINCT over a projection that keeps only the table, which is exactly what demanding a single target makes safe. A field with no path whose named type is itself bound to a table resolves to that table, which is where an ordering column named on a list field lives; the named type read is the one the author wrote, taken off graphitron_field_synthesis where a macro rewrote the field’s type expression, so a connection field’s columns are the element type’s rather than the wrapper’s. That last clause is half a rule and the half it is missing is stated here rather than left to be rediscovered: a connection type the author declared in the SDL has no synthesis row, so this arm resolves it to the wrapper, which binds nothing, and an ordering column named on such a field has no scope. intent_field_navigated_type is the relation that states the whole rule and every sibling site reads it; this arm is the one site that cannot, and the reason is the anti-join two clauses below. That anti-join correlates intent_authored_field_claim, a recursive view, once per driving row, and it is cheap only under the plan H2 picks when the navigated type is a literal expression over base tables. Every form that names a derived relation in that position was measured and every one of them flipped the plan: joining intent_field_navigated_type costs 4308 milliseconds against this shape’s 89, and reaching it by scalar subquery, reaching intent_connection_element_type by scalar subquery, and spelling the connection shape inline as a base-table subquery each failed to finish inside 200 seconds. So the fix here is a rewrite of the anti-join and not a repointing, and it is filed as its own item rather than taken in passing. A leaf field with no path resolves in its own parent’s binding, which is the scope every column-bound field of a table-bound type resolves in, and the leaf guard is what keeps this rule clear of the one above rather than a ranking between them: that rule reads an OBJECT named type and this one reads a SCALAR or ENUM. The two read the named type at different stages, this rule the field’s current one and that rule the expression the field was written with, so a macro that turned an object-typed field into a scalar-typed one would let both fire at a coordinate. None does, and if one ever did it would announce itself as two rows at one site, which the anchor test asserts against, rather than as a silent pick. Both binding rules read intent_resolved_type_binding rather than the @table population, because a column name resolves against whatever table stands for the type and a type standing for a @routine chain’s result has one; that is what lets a routine-returned type’s own scalar fields resolve without the author restating the routine as a @table. The resolution is also what keeps the rules one row per site: it collapses a type its @table and its routine return agree on to one binding, where a provenance-keyed relation would hand this view two. The single-table demand each rule already carries is unchanged, an ambiguous binding staying a site with no answer here. A field whose named type is an unbound object resolves nowhere, so a column name written at a nesting type’s site has no answer here yet; no consumer asks one, and the rule that would answer it is the type-grain nesting question rather than a fourth rule at this grain. A field carrying reference steps takes the first rule or nothing: a path reaching no single table must not fall back on the parent, because resolving a name against the parent there points the author at the wrong end of a join. The three rules do not carry the same guards and that is not an inconsistency. The named-type rule guards against a root parent, a named type of any kind but OBJECT, an ambiguous binding, an authored claim and a @pivot, because navigating to another type’s binding is exactly what an authored claim diverts. @pivot is the one claim that rule names directly, because the claim vocabulary has no arm for it yet and a pivoted field reads its columns from the pivot rather than from the type it names; the explicit guard folds into the anti-join the day that arm lands. The parent rule guards against none of those, because a field’s own parent scope exists whatever claims the field, and the structural classifier reads it precisely so a diagnostic can say "would classify as a table column; @service overrides it". A consumer joining this relation puts it first in its own FROM clause; intent_column_match_claim’s comment carries the measurement, and the shape it warns against is the one a reader reaches for. Masking is a consumer’s join and never a rule here: the authored-conflict silence intent_field_column_table adds sits in that view, and folding it in would silence the column-match classifier at a contested coordinate, where its raw reading is the whole point. Materialized: this relation is a table refilled from intent_field_column_scope_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from every rule’s base relation

type_name (CHARACTER VARYING, not null)

the site’s owning type, the field’s parent

field_name (CHARACTER VARYING, not null)

the site’s field name within the owning type

basis (CHARACTER VARYING, not null)

which rule resolved this site: PATH_TERMINAL (an authored @reference path’s terminal element), NAMED_TYPE_TABLE (the field’s named type’s own binding), PARENT_BINDING (the field’s own parent’s binding). A closed vocabulary of three disjoint rules, so it is also which boundary the site fell inside, and the column that lets a consumer tell an override from the parent’s own scope without re-deriving either

table_source_name (CHARACTER VARYING, not null)

the resolved table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, not null)

the resolved table’s SQL schema

table_name (CHARACTER VARYING, not null)

the resolved table’s SQL name. With the two columns above this is sql_table’s full key, so the table’s columns are one join away

intent_field_column_scope_live (view)

This states the rule and is evaluated on demand. The canonical name intent_field_column_scope beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_field_column_scope.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_field_column_scope.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_field_column_scope.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_field_column_scope.field_name, whose comment carries what the value means

basis (CHARACTER VARYING, nullable)

the basis of a row of this rule, materialized into intent_field_column_scope.basis, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_field_column_scope.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_field_column_scope.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_field_column_scope.table_name, whose comment carries what the value means

intent_field_column_table (view)

Which table a column name written at a field’s site resolves against, when that table is not the one the field’s own parent is bound to. The question an editor asks at a @field(name:) or @defaultOrder(fields: [{name:}]) site, and the resolution three LSP arms (completion, hover, the field-member diagnostic) each used to ask a projected per-permit switch. The navigation itself is intent_field_column_scope’s and no longer restated here: this view is that relation read as an override, its two non-parent bases carried through as RESOLVE rows and its parent-binding rows dropped. Deliberately narrow, which is what dropping them means: a field whose column names resolve against its parent’s own binding contributes no row, because a reader already holding the parent’s binding needs no relation to tell it so, and stating that case here would make this view a copy of the scope keyed one grain down. Absence therefore means "the parent’s own scope answers", which is the reading every consumer already falls back to; only a row overrides it. Two rules produce silence, meaning "no column name resolves here, and the parent’s scope must not stand in", and both are this view’s own rather than the scope’s: a coordinate whose classification the author has already contested, and an authored path that reaches no single table, the second read as the scope answering a path-carrying field with no terminal. The conflict silence stays here on purpose, because the column-match classifier reads the same scope and its raw reading at a contested coordinate is what lets a diagnostic name the override. The silences are structural, never a reading of the rejection residue: a derivation that asked the residue whether a coordinate had been reported would go quiet the day that family drains, and this relation’s meaning must not depend on where a message currently lives.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the site’s owning type; the parent whose binding this row overrides

field_name (CHARACTER VARYING, nullable)

the site’s field name within the owning type

disposition (CHARACTER VARYING, nullable)

RESOLVE when the row names a table to resolve column names against, SILENT when it names none and the parent’s scope must not stand in. A closed two-value fork, which is what a consumer switches on; the basis it came from is the next column. Determined by basis rather than independent of it, and carried anyway because the fork is the reading every consumer needs and re-deriving it from a five-value vocabulary at each of them is how the two would drift

basis (CHARACTER VARYING, nullable)

which rule produced this row: PATH_TERMINAL (an authored @reference path’s terminal element), NAMED_TYPE_TABLE (the field’s named type’s own binding), UNRESOLVED_PATH (an authored path reaching no single table), CONFLICTED (the coordinate’s claims are mutually exclusive). A closed vocabulary, and the column that lets a consumer explain its answer and a test pin which rule fired without asserting on the table it happened to reach

table_source_name (CHARACTER VARYING, nullable)

the resolved table’s catalog partition, the first column of the sql_table key this row names; NULL on every SILENT row

table_schema (CHARACTER VARYING, nullable)

the resolved table’s SQL schema; NULL on every SILENT row

table_name (CHARACTER VARYING, nullable)

the resolved table’s SQL name; NULL on every SILENT row. With the two columns above this is sql_table’s full key, so the columns themselves are one join away

intent_field_demand_rule (view)

The types whose fields require a classification verdict, one rule literal per arm. Type-keyed by design: every rule shipped so far is a property of the parent type, so this is the rule’s authored grain and the field grain is a join in the resolved view, legible as a projection rather than materialized into the rule literal. The root arm is keyed by the root operation binding, not the conventional names, so it states the intended rule; today’s walk dispatches on the literal names Query and Mutation, and a renamed root’s fields are a known demanded-but-unregistered population the shadow agreement pins. The producer arm covers the payload types whose producers capture can see (@service and @externalField references that decoded to a class, and every DML @mutation payload); a DELETE payload’s data field is thereby demanded even though today’s walk loses its verdict on every path but the ID-element repayment, which is the other pinned population. The underscore masks transcribe the walk’s short-circuit: an underscore-prefixed type never classifies, whatever it carries, while a root binding is checked before that short-circuit and stays unmasked. Each rule’s witnesses live one join away in the arm’s base relation; this view carries the rule key only, so no arm’s witness columns go nullable on the others.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried through from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the parent type whose fields the rule demands verdicts for

rule (CHARACTER VARYING, nullable)

why the fields are demanded; a closed vocabulary (ROOT_OPERATION, TABLE_TYPE, ERROR_TYPE, PRODUCER_PAYLOAD) the reading side decodes into a typed value

intent_field_error_channel (view)

Which coordinate has an error channel and what the channel is made of: one row per producing field whose returned type declares an error channel, total over them. The grain is the producing coordinate and not the payload, because a channel is something a field routes its throws into and two fields returning one payload are two channels, which is exactly the population the constant-name dedup groups over. Which field of the payload is the channel is intent_errors_field’s answer and the pick is this relation’s: a payload declaring several errors-shaped fields routes through the first in declaration order, so the join takes the minimum ordinal and carries it, the walk’s first-wins rule stated as a column rather than left implicit in a scan order. What the relation carries is the channel’s inputs and never its minted name. mappingsConstantName is a generated identifier, and a column holding one would make this relation a second site where a naming formula is spelled; the formula’s one home is GeneratedUnits, which reads these columns. That is the whole reason the payload class is here in binary form and the payload type in SDL form: the fold that mints the constant takes one of them depending on the transport, and a store that carried the folded result instead would have decided which. The transport is a decode over three facts and a precedence, not a transcription of the classifier’s control flow. A root @service field rides the typed Outcome wrapper, whichever shape its payload has, so that arm is tested first and wins over the carrier arm where both would answer; a payload the carrier recognition admits under the producing family is a directiveless structural wrapper whose catch arm ferries through graphql-java’s localContext; anything else constructs a developer payload class at the catch site. The precedence is real and stated rather than partitioned away, a root @service payload being a carrier under its own family as well. Ambiguity in the backing class is an arity and not a pick, on intent_bound_table’s terms: a payload two populations back differently reports the count and no class, so a reader needing one class sees the contest here instead of receiving a silent winner, and intent_type_backing is where the contesting classes are rows. A coordinate whose payload declares no errors-shaped field is absent rather than present with a null transport, this relation being total over channels and not over producers; a producer with no channel is a fact intent_field_payload_producer already carries.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, nullable)

the type declaring the producing field; a root operation type where the producer is a root write, the parent type where it is a child @service field

field_name (CHARACTER VARYING, nullable)

the producing field’s name; with the type, the coordinate whose throws this channel routes

transport (CHARACTER VARYING, nullable)

how the catch arm hands errors back, a closed three-value domain: OUTCOME_WRAPPER for a root @service field, whose errors ride the typed Outcome the fetcher returns; LOCAL_CONTEXT for a structural carrier, whose catch arm returns a null-column sentinel and ferries the throwables through graphql-java’s localContext; PAYLOAD_CLASS for a channel whose catch arm constructs a developer payload class and slots the list into it. Decoded, in that order, from whether the coordinate is a root @service field, which is intent_field_payload_producer.root_operation being present, and whether the carrier recognition admits the payload under this family; the order is a precedence and not a partition, both arms answering for a root @service payload

family (CHARACTER VARYING, nullable)

which producing directive returns the payload, a closed three-value domain: SERVICE (@service), DML (@mutation), ROUTINE (@routine); carried from intent_field_payload_producer on intent_carrier_data_field.family’s terms

payload_type_name (CHARACTER VARYING, nullable)

the SDL type the producing field returns, unwrapped; the type declaring the errors field, and the fold’s input on the two transports that mint from an SDL name

errors_field_name (CHARACTER VARYING, nullable)

which field of the payload is the error channel; the first errors-shaped field in declaration order where the payload declares several, all of which are rows on intent_errors_field

errors_field_ordinal (INTEGER, nullable)

that field’s declaration index within the payload, carried from intent_errors_field; the ordinal that decided the pick, and on the payload-class transport also the canonical constructor’s errors-slot parameter index

payload_class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class the channel routes through, from intent_type_backing, and the fold’s input on the payload-class transport. NULL where the payload has no backing class and equally where it has more than one, an ambiguous backing being no backing at all; the count says which, and the candidates are rows on intent_type_backing

payload_classes (INTEGER, nullable)

how many distinct classes back the payload type; 1 is what a payload-class transport requires, 0 is a payload no population backs, and more is a contest intent_type_backing_conflict names. An arity rather than a pick, so a reader’s refusal stands on a number it did not have to count

intent_field_exemption_rule (view)

The types whose fields are intentionally not demanded, a reason per arm, type-keyed like the demand rules. Arms are unmasked against each other and against demand, so overlapping readings survive as rows (a structural connection type is also a directiveless object, and both rows are true); one-reason-per-coordinate is the resolved view’s job, per the same masked-reading argument the column-match classifier records. The interface arm is the census’s largest population (no interface’s fields ever classify); the input arm makes the trace-only input coordinates explicit rows; the underscore arm transcribes the walk’s name short-circuit at the field-bearing object kind (interfaces and inputs are already covered by their kind arms); the machinery arm is the structural connection recognition (an object with an edges field whose object element has a node field, reached by some carrier field, plus that shape’s edge type, plus the SDL-declared PageInfo when any promotion would fire), whose fields the connection emitter owns; the nesting-target arm is the walk’s own absence-shaped rule (a plain object with no classifying directive, no root binding and no store-visible producer resolves through its embedding edge, or is an orphan whose rejection surfaces at the referencing field), stated by its own predicate rather than as an anti-join of the demand view, so the two relations state their rules independently and the resolved view owns their meet. Types bound only through the reflection fixed point (accessor chains, record-composite carriers) are deliberately in neither this view nor the demand view; that population is the shadow residue whose store-side closure lands with the binding-walk classifier migration.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried through from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the parent type whose fields the rule exempts

reason (CHARACTER VARYING, nullable)

why the fields are exempt; a closed vocabulary (INTERFACE_TYPE, INPUT_TYPE, UNDERSCORE_TYPE, CONNECTION_MACHINERY, NESTING_TARGET). Named reason, not classifier: classifier is reserved family-wide for classification kinds

intent_field_navigated_type (view)

Which type a field’s own generated SQL navigates as: the type whose binding, whose members and whose columns a rule at this coordinate should read, as against the type the field’s signature happens to name. The two differ wherever a wrapper stands between the field and what it delivers, and a rule that reads the signature at such a coordinate reads the wrapper’s facts, which are none. Total over graphql_field: every field navigates as something, so a consumer joins this rather than left-joining it, and the fallback rung is what makes that true. Three rungs in precedence. The expression the author wrote, where a macro rewrote the field’s type: graphitron_field_synthesis holds that expression and its list and non-null wrappers are stripped here, so a field the CONNECTION macro expanded navigates as the element the author named. Below it the structural connection, intent_connection_element_type keyed by the field’s current named type, which is what answers for a connection type the author declared in the SDL and the generator therefore synthesised nothing for. Below that the field’s own named type, which is the ordinary case and every field that returns what it says it returns. The upper two rungs agree wherever both fire, a synthesised connection’s edges.node being the element the authored expression named, so the precedence between them is a tie-break rather than a disagreement; it is stated as a precedence anyway because the authored expression is the more direct evidence and because a macro that expanded to something other than a connection would need it. This relation is the correction of a resolution that had five spellings. The COALESCE over the synthesis record was written out at five sites, and all five read the same way: a connection navigates as its element when the generator built the connection, and as the wrapper when the author wrote it. The second half of that sentence is a silence and not a rule. A field returning an author-declared connection type resolved to a type binding no table, so it had no scope table, so its arguments had no scope, so a filter argument on it resolved no column and the condition membership fold could not see it, all from a rule that claims to navigate connections and only navigated the ones with a synthesis row. Four of the five sites read this relation now and are correct at both halves: intent_field_scope_table, intent_field_participant_scope_table, intent_routine_return_binding and intent_mutation_routine_seat. The fifth is intent_field_column_scope’s named-type arm, which still spells the COALESCE and still carries the silence, not because anyone preferred it that way but because that arm’s anti-join against a recursive view is cheap only under the plan H2 picks when the navigated type is a literal base-table expression; its own comment carries the measurements and the item that owns the rewrite. So the count to hold this relation to is four, and the sixth spelling it exists to prevent is the one nobody has written yet. The basis column says which rung answered, so a test can pin the rule rather than only the answer. What this relation does not do is resolve anything: it names a type, and whether that type binds a table, holds polymorphic members or declares columns is each consumer’s own join. Nor does it look through a polymorphic container; a field returning a union navigates as the union, and the members are intent_poly_member’s answer read from that name. Declared before intent_routine_return_binding because that is the first of its readers, and the ordering here is a dependency rather than a reading order.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_field; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, nullable)

the type owning the field

field_name (CHARACTER VARYING, nullable)

the field whose navigation this row states; with the two columns above, the grain, and one row per field of the graph

basis (CHARACTER VARYING, nullable)

which rung answered, in a closed vocabulary of three: AUTHORED_EXPRESSION from the pre-expansion type expression a macro rewrote, CONNECTION_ELEMENT from the structural edges.node shape of a connection type the author declared, NAMED_TYPE from the field’s own named type. Provenance and a pinnable rule both; a reader that means one of them filters on it and owns having chosen

navigated_type_name (CHARACTER VARYING, nullable)

the type name the field navigates as, wrappers already stripped. A name and never a binding, so a consumer joins intent_resolved_type_binding, intent_poly_member or graphql_type on it according to what it actually needs to know

intent_field_participant_scope_table (view)

Which table one participant of a field’s polymorphic named type binds: the table that participant’s own branch of the field’s generated SQL is rooted in. A field returning a union, or an interface carrying no @table of its own, resolves to several tables rather than to one, and the classifier answers it by lowering the field once per table-bound participant, each against that participant’s own table; this relation is that population, one row per participant the field’s named type holds a binding for. The participant’s type name is a key column and not provenance, because it is what a consumer needs beyond the table: the generated condition method is named after the participant rather than after the container, so two participants of one field are two named units and a row carrying only a table could not tell a consumer which. Disjoint from both of intent_field_scope_table’s ranked rungs by construction rather than by precedence, which is why that relation unions this one in outside its window instead of ranking it as a third rung. The container binding nothing of its own is this relation’s own precondition, and it is exactly what separates the shape from the single-table discriminated interface, whose interface does carry @table and whose participants therefore share one table and one filter surface; a field carrying a @mutation(table:) spelling that resolves is excluded for the symmetric reason, the author having said which table the coordinate’s SQL binds against. Each participant’s binding must be unambiguous, on intent_field_reference_discovery’s terms and for the reason the ranked rungs give: a branch is a statement and two candidate tables are two different statements. A member with no binding at all contributes no row and no rejection here, the container whose every member must bind being the type classifier’s invariant and not this relation’s; a partially bound container is therefore incomplete here and rejected there, which is the division of labour every rule relation in this family keeps. Two participants binding one table are two rows, the grain being the participant; a consumer that wants tables takes them through intent_field_scope_table, whose projection of this relation is distinct on the table for that reason. Nothing here says any argument or name at the coordinate is column-shaped: this relation answers where each branch is rooted, and what each branch filters on is the argument-site resolution’s answer, reached one table at a time through that projection. Read cost, measured on the sakila example schema at 917 fields and 267 arguments, 128 rows out, five interleaved sweeps with result reuse off, so every figure carries an execution count above one and a standard deviation. The shape that ships joins the membership directly onto the stripped type expression and costs 47 milliseconds. Projecting that expression into an inner derived table first and joining the membership on the column costs 27, a 42% saving that is measured, reproduced, and deliberately not taken; the paragraph after this one is why, and it is the more useful half of the measurement. Two controls decided the rest. Driving from the 52 membership rows rather than the 917 fields, which reads like the obvious win, measured 29 milliseconds with three times the spread, so the smaller driver bought nothing. And the shipped shape with both exclusions removed measured 42 against 47, so the two anti-joins are about a tenth of the cost and the expansion is the rest; both children price under a millisecond, the membership at 0.3 and the binding at 0.04, which is what says there is no expensive child to register underneath this. The projection was called unshippable here for two builds and it ships now, which is worth the sentence it takes to say what changed, because the reason it was unshippable was real. The projection changes which plan H2 takes for this relation and for the two above it, and under that plan the registered read of intent_resolved_type_binding visited more rows than reading its source view would, for this relation, intent_field_scope_table and intent_argument_scope_table_live alike; DerivedReadCostTest asserts the opposite over every such pair, so the projection failed the verification build deterministically. What closed it was not a rewrite but an index. The registration on intent_resolved_type_binding shipped without one, which cost nothing while every reader spelled its type expression inline, H2 pushing that expression down into the probe, and stopped costing nothing the moment the expression became a column: a join onto a projected column is one the planner may satisfy by scanning. ix_resolved_type_binding_type is the probe those readers actually make, and with it this relation and the field-grain scope table above it are both monotonic again. The same measurement carries its own warning, and it is the fact model’s: three readers further down the write family are still counted non-monotonic through that binding while their wall clocks did not move at all, so the counter and the clock disagree there and DerivedReadCostTest’s pinned set records which is which. This relation’s own clock is what it costs: the projection took it from 47 milliseconds to 63, driving from intent_field_navigated_type rather than from graphql_field, which is the shape that measured best of the three tried; joining that relation while still driving from the field list measured 228. Read the sibling essay on intent_field_scope_table beside this, because the two look contradictory and are not: it was retired at the field grain once the far side of that join became a table, and there is nothing to re-evaluate per driving row when the far side is stored. intent_poly_member is a view, so the projection pays here, and the condition is what generalises rather than either verdict. Not registered, and the reason is reader count rather than cost: one relation names this one, and one names that, so a registration here would pay one refresh to save one evaluation. The arm does raise intent_field_scope_table from 16 milliseconds to 59, which is the honest price of a question the store could not answer at all before, paid once per refresh of the argument scope it feeds. When the condition membership fold arrives as a second reader that trade changes and is worth re-measuring then. The population is stated structurally and not narrowed to where an emitter exists, on intent_node_id_encode’s terms: a child field whose named type is a multi-table container has the same fact as a root field with that type, whether or not the generator carries a per-participant filter surface there, and narrowing the rows to today’s emitter would make this relation track emitter maturity instead of the schema.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_field

type_name (CHARACTER VARYING, nullable)

the type owning the field whose branches this row states; not the polymorphic container, which is the field’s named type

field_name (CHARACTER VARYING, nullable)

the field whose named type is the polymorphic container

member_type_name (CHARACTER VARYING, nullable)

the participant this row answers for: the union member or interface implementor whose table the branch is rooted in. Part of the grain, and what a consumer minting a per-participant unit name reads; the participant’s position within its container is intent_poly_member’s and is not restated here

table_source_name (CHARACTER VARYING, nullable)

the participant table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the participant table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the participant table’s SQL name; with the two columns above this is sql_table’s full key, so the branch’s own columns are one join away

intent_field_payload_producer (view)

Which coordinate produces a value and what type it returns: one row per field carrying a producing directive, with the directive’s family and the unwrapped SDL type the field’s value arrives as. The grain is the coordinate, which is what separates this from intent_carrier_data_field’s producer reading: that view asks which payload types a mutation root returns and folds the coordinates away, so a payload two fields return is one row there and two here. Both readings are wanted and only this one can key a fact to the field an author is looking at, so the fold is the reader’s and this relation does not perform it. A @routine field is DISTINCT because a chain applies the directive once per hop and the coordinate produces one value however many hops reached it, the hops being intent_field_chain_node’s rows. Where the coordinate sits is a column rather than a filter, for the same reason the family is: a root write and a child @service field are the same fact under different readings, and the two policies that turn on the position (the carrier scan wants root mutations, the error channel’s transport wants root @service) each name what they mean. One column carries it and not two, the operation being the discriminator and its absence the predicate, so a reader asking only whether the field sits at a root writes that as a null test rather than reading a boolean that would have to agree with it. A type serving as two root operations at once reports the alphabetically first, which keeps the grain at the coordinate; nothing in the schema forbids the shape and nothing in the generator has met it. @externalField is deliberately absent: it names a class member that answers an already-produced value rather than a directive that produces one, and intent_field_producer_reference is where the two meet as method references. Absence here means the field carries none of the three directives, not that it has no value.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, nullable)

the type declaring the producing field

field_name (CHARACTER VARYING, nullable)

the producing field’s name; with the type, the coordinate this row is about

family (CHARACTER VARYING, nullable)

which producing directive the field carries, a closed three-value domain: SERVICE (@service), DML (@mutation), ROUTINE (@routine). A field carrying two is a row per family rather than a pick, on intent_carrier_data_field.family’s terms

payload_type_name (CHARACTER VARYING, nullable)

the unwrapped SDL type the field returns, carried from graphql_field.named_type; the payload whose shape every carrier and channel reading starts from

root_operation (CHARACTER VARYING, nullable)

which root operation the declaring type serves, QUERY / MUTATION / SUBSCRIPTION, or NULL where it serves none, which is what a reader asking only whether the field sits at a root tests. The position two policies turn on, and stated here so neither has to join graphql_root_operation to ask. The alphabetically first where a type serves two, which keeps this relation at the coordinate’s grain

intent_field_producer_method (view)

The census method a field’s authored Java reference names: intent_field_producer_reference resolved against jvm_method, one row per method the reference matches. A use-keyed resolution over a source-keyed census, which is the shape an authored coordinate reaching into the classpath always takes here, and it states the resolution alone: which class the method’s return names is jvm_method_return_type_ref’s answer, one join further on. Which directive named the method, how the two arms coalesce and where the @externalField omitted-method fallback is applied are all the reference relation’s, stated in its comment; this relation adds the census match and nothing else, so a reader wanting the authored names without the match reads the reference and is not made to care whether the class was scanned. Ambiguity is rows and never a decline, as on intent_bound_table: a reference matching two overloads is two rows and candidates says so. That is the one place this relation departs from the walk it replaces, which takes whichever matching method the reflection API hands back first, in an order the JVM does not specify, so the walk’s answer for an overloaded name is unstable rather than merely arbitrary. The intended reading is that a reference matching more than one method is a rejection, and what a rejection needs is the arity, which is why this relation states it rather than picking. Absence has two causes and one join separates them: no jvm_class row under the graph’s sources means the census never reached the class (the scan’s filters, an entry nothing read, the generated jOOQ package), while a class row with no method row means the class declares no method of that name. Nothing here judges the reference beyond matching it. The census carries neither a static flag nor a lifter’s parameter shape, so an @externalField row does not assert the method satisfies that directive’s contract, and a nested class an author spells Outer.Inner matches nothing, the census writing the $ the JVM writes and skipping nested classes anyway.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the directive relation the arm reads

type_name (CHARACTER VARYING, nullable)

the referring field’s owning type

field_name (CHARACTER VARYING, nullable)

the referring field’s name within the owning type

declared_via (CHARACTER VARYING, nullable)

SERVICE or EXTERNAL_FIELD: which directive named the method, a closed two-value vocabulary. Carried rather than derived because the pair of names a row resolves cannot tell the two apart, and they are not interchangeable: a service method is invoked for the field’s value, an external field’s is invoked once for the jOOQ Field the generator selects. A coordinate carrying both directives is a conflict intent_authored_claim_conflict already reports, and here it is simply two references, each resolved on its own, neither winning

source_name (CHARACTER VARYING, nullable)

the resolved method’s classpath entry, as on jvm_method; the census partition the graph reached through store_graph_source, and the reason another graph’s entries cannot answer this graph’s reference

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class declaring the resolved method, matched against the reference exactly. Java names are case-sensitive, so a misspelling resolves to nothing rather than to a near match

method_name (CHARACTER VARYING, nullable)

the resolved method’s name: the reference’s method argument, or the SDL field’s own name where an @externalField omitted it

descriptor (CHARACTER VARYING, nullable)

the resolved method’s raw JVM descriptor, jvm_method’s overload discriminator and the whole of what tells two rows of one reference apart. The column a reader carries forward to reach the method’s parameters and the classes its declared return type names

candidates (INTEGER, nullable)

how many census methods this reference matches, this row being one of them; 1 on an unambiguous reference. Partitioned by the reference and not by the coordinate, so a field carrying both directives does not report one arm’s overloads as the other’s. Two overloads and one class declared by two classpath entries both raise it, which is one fact from a reader’s side: the reference names more than one method. Stated as a column rather than left to each reader’s own count, on intent_bound_table.candidates' terms, whether a reference is unique being what decides the reading

intent_field_producer_reference (view)

The Java method a field’s authored directive names, before anything checks whether it exists: @service and @externalField coalesced, one row per application. Named apart from its resolution because the two answer different questions and one of them survives an unreachable class. A surface that must name the declaration a field binds to needs the reference, which the author wrote and which is a fact whether or not the classpath census reached the class; a surface that needs the method’s arity or wants to know the reference is ambiguous needs intent_field_producer_method, which is this relation resolved against jvm_method and therefore empty exactly where the census fell short. Splitting them also gives the @externalField omitted-method fallback one home: graphitron_external_field’s own comment defers that default to a derivation, and this is it, so no reader repeats the coalesce. Two arms coalesced by a view rather than one relation over a merged base, because which directive named the method is not recoverable from the pair of names and the two say different things about how the method is reached; declared_via carries it, on jvm_class_supertype.declared_via’s terms. Nothing here judges the reference: a coordinate carrying both directives is two rows, neither winning, and the conflict is intent_authored_claim_conflict’s to report.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the directive relation the arm reads

type_name (CHARACTER VARYING, nullable)

the referring field’s owning type

field_name (CHARACTER VARYING, nullable)

the referring field’s name within the owning type

declared_via (CHARACTER VARYING, nullable)

SERVICE or EXTERNAL_FIELD: which directive named the method, a closed two-value vocabulary, carried forward to intent_field_producer_method where its full argument is written

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name the reference spells, exactly as authored. Unresolved: no row here asserts the class is on the classpath, and a misspelling is a row like any other

method_name (CHARACTER VARYING, nullable)

the method name the reference spells: the directive’s method argument, or the SDL field’s own name where an @externalField omitted it. An @service missing either name has no row at all, that directive having no fallback

intent_field_reference_discovery (view)

The foreign key an omitted @reference path discovers: for a field whose parent type and named type are each bound to a table, every foreign key connecting those two tables in either direction. This is the resolution the walk runs where a field carries no path element, and sql_referential_constraint’s own comment defers it here, "exactly one foreign key between these two tables" being a derivation over that relation rather than a captured fact. Separate from intent_field_reference_step_hop because that view resolves what an author wrote and this one answers where nothing was written; the hop view names this as a resolution it deliberately does not perform, so its silence is not the absence of a discovery. Neither endpoint is re-derived here. The arriving table is intent_field_column_scope’s named-type rule, which reads the written type expression through graphitron_field_synthesis so a synthesised connection field navigates as its element type, demands an OBJECT named type and an unambiguous binding, and excludes the coordinates an authored claim, a @pivot or an authored path diverts; restating any of that would be a second spelling of the navigation that view exists to state once. That rule’s own comment carries what it does not answer for, an author-declared connection, and why it alone among its siblings still spells the navigation rather than reading intent_field_navigated_type. The departing table is the parent’s own binding, demanded unambiguous for the reason the arriving one is: a discovery between endpoints that are not certain is not the pair the walk would have had in hand. One row per connecting key and not two, a foreign key connecting a pair once whichever end declares it, and fk_on_from says which end that is; a self-referential key therefore needs no special case, the same-table pair being excluded outright. Excluded because the walk excludes it, comparing the two table names case-insensitively and nothing else, so two like-named tables in different schemas are one table to this rule as they are to the walk. Both names are catalog values reached through derived views, and a derived view does not forward a fold, so the comparison joins sql_table on its key at each end and reads the fold there; that costs two lookups on a primary key and keeps the fold a property of the relation that owns the spelling. The self-referencing field states its key explicitly or is rejected with that advice. Absence covers several things and none of them is "the discovery found nothing in particular": no foreign key connects the endpoints, or an endpoint is unbound or ambiguously bound, or the coordinate is one the named-type rule excludes. The walk’s other element-less arm needs no exclusion here: where the departing table is a table-valued function the walk name-matches instead of discovering, and a routine result declares no foreign keys, so such a coordinate contributes no rows on its own. The departing endpoint reads intent_resolved_type_binding, as the arriving one already does through the navigation view, so a parent bound by a @routine chain’s return rather than by a written @table is the same endpoint here; where that chain landed on a function result the sentence above is why the pair still finds nothing, and where it landed on a stored table through a hop the discovery is the ordinary one.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the navigation view

type_name (CHARACTER VARYING, nullable)

the type owning the field the path was omitted on; also the type whose binding is the departing end

field_name (CHARACTER VARYING, nullable)

the field name within the owning type

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition, first column of its sql_table key

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name; the parent type’s own binding

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name; the binding of the type the field names

constraint_name (CHARACTER VARYING, nullable)

the foreign key connecting the two tables, which is what an author would write into a {key:} element. Its own sql_referential_constraint key is this name under whichever endpoint declares it, which fk_on_from says

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key, FALSE when the arriving one does; the hop’s direction, and what completes the constraint’s key from the two endpoint triples

candidates (INTEGER, nullable)

how many foreign keys connect the two tables, this row being one of them; 1 is what the walk requires of a discovery, and a larger number is what its own "which foreign key did you mean" rejection counts. Stated as a column rather than left to each reader’s count, because whether the discovery is certain decides the reading and a reader that counted for itself would be re-deriving the resolution’s arity

intent_field_reference_step_hop

One @reference path element’s local resolution: every table-to-table hop the element could express, before anything decides which table the chain has actually arrived at. Both arms of authored navigation are here. A key element resolves its constraint name the way the generator’s resolver does: a leading qualifier, split off by capture and stored beside the value, binds hard, an unqualified name matches the SQL constraint name, and only where no SQL constraint in this graph’s sources answers that name does the generated Keys-class constant become eligible, which is the resolver’s namespace precedence rather than a looser match on either. That qualifier does not name the constraint’s own schema, a constraint having none of its own; it names which schema’s table holds it, which is why it binds against the constraint’s table_schema and not against anything the constraint itself is namespaced by. A table element resolves its spelling through intent_spelled_table and pins the arriving side to it, leaving the foreign key to be discovered. A table element has a second resolution beside that one, for the departure a foreign key cannot describe: a table-valued function’s result declares no constraints, so a hop leaving one is keyed by matching the arriving table’s primary-key column names against the columns the function exposes, which is the rule the generator applies there and the only one available. That arm pins the arriving side to the spelling exactly as the foreign-key arm does, and enumerates as candidate departures every FUNCTION-typed table in the graph’s sources that intent_name_matched_key_pair pairs wholly to the arrival. The pairing rule lives there rather than here because this arm is not its only asker, a carrier’s inferred hop reaching it from a coordinate that authored no element; what this arm contributes is the two ends, and it demands only that the pairing come up total. An arrival with no primary key has nothing to match and yields none, which is the same shortfall the generator reports in the name-match vocabulary rather than in the foreign-key one, and the columns behind a shortfall are rows on that relation for a reader that has to name them. The two table arms cannot produce the same row, a function result declaring no foreign key for the other arm to discover. Both foreign-key arms enumerate the hop in both orientations, because a foreign key is a hop in either direction and which one an element means depends on where the chain stands; a self-referential key is one hop and not two, since both orientations land on the same table and the walk’s cardinality hint chooses join columns rather than a destination. Separate from intent_field_reference_step_target because the local resolution has no recursion in it: keeping the two apart is what lets that view’s recursive term be a single join instead of a copy of these arms. Materialized: this relation is a table refilled from intent_field_reference_step_hop_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_field_reference_step

type_name (CHARACTER VARYING, nullable)

the type owning the field the @reference is applied to

field_name (CHARACTER VARYING, nullable)

the field the @reference is applied to

ordinal (INTEGER, nullable)

the owning @reference application’s ordinal, since the directive is repeatable

position (INTEGER, nullable)

the element’s 0-based position within its application’s path

via (CHARACTER VARYING, nullable)

which arm resolved the element: KEY where it named a constraint, TABLE where it named a table and a foreign key connects the two, NAME_MATCH where it named a table and the departure is a function result, whose hop is keyed by column name because it declares no constraints. KEY and TABLE are the author’s two spellings; NAME_MATCH is the second reading of the table spelling rather than a third thing to write. The element’s own written form is one join back to graphitron_field_reference_step; this column is the resolution’s reading of it

key_matched_by (CHARACTER VARYING, nullable)

for a KEY hop, which namespace answered: SQL_NAME (the SQL constraint name) or JOOQ_NAME (the generated Keys constant). NULL on a TABLE or NAME_MATCH hop, neither of which names a constraint. Makes the resolver’s namespace precedence visible data instead of a hidden pick, as the column-match claim’s own tier column does

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition, first column of its sql_table key

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name; a candidate departure, not yet a fact about the chain. On a NAME_MATCH hop the candidacy is wider than on the other arms, being every function result in the graph’s sources that exposes the arrival’s key columns rather than the endpoints of one named constraint, which costs nothing until a chain says where it actually stands

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name

constraint_name (CHARACTER VARYING, nullable)

the foreign key the hop joins on, named or discovered. Its own sql_referential_constraint key is this name under whichever endpoint declares it, which fk_on_from says. NULL on a NAME_MATCH hop, which joins on no foreign key. The constraint such a hop does key by is the arriving table’s primary key, and that is left to the join rather than carried: sql_primary_key is keyed by the table, so the arriving triple this row already carries reaches it directly, and repeating it here would be the denormalisation the referenced-side discipline declines

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key, FALSE when the arriving one does; the hop’s direction, and what completes the constraint’s key from the two endpoint triples. NULL on a NAME_MATCH hop, where there is no foreign key to sit on either side and the direction is fixed by the arms themselves, a function result being always the departure

intent_field_reference_step_hop_live (view)

This states the rule and is evaluated on demand. The canonical name intent_field_reference_step_hop beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_field_reference_step_hop.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_field_reference_step_hop.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_field_reference_step_hop.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_field_reference_step_hop.field_name, whose comment carries what the value means

ordinal (INTEGER, nullable)

the ordinal of a row of this rule, materialized into intent_field_reference_step_hop.ordinal, whose comment carries what the value means

position (INTEGER, nullable)

the position of a row of this rule, materialized into intent_field_reference_step_hop.position, whose comment carries what the value means

via (CHARACTER VARYING, nullable)

the via of a row of this rule, materialized into intent_field_reference_step_hop.via, whose comment carries what the value means

key_matched_by (CHARACTER VARYING, nullable)

the key_matched_by of a row of this rule, materialized into intent_field_reference_step_hop.key_matched_by, whose comment carries what the value means

from_source_name (CHARACTER VARYING, nullable)

the from_source_name of a row of this rule, materialized into intent_field_reference_step_hop.from_source_name, whose comment carries what the value means

from_schema (CHARACTER VARYING, nullable)

the from_schema of a row of this rule, materialized into intent_field_reference_step_hop.from_schema, whose comment carries what the value means

from_table (CHARACTER VARYING, nullable)

the from_table of a row of this rule, materialized into intent_field_reference_step_hop.from_table, whose comment carries what the value means

to_source_name (CHARACTER VARYING, nullable)

the to_source_name of a row of this rule, materialized into intent_field_reference_step_hop.to_source_name, whose comment carries what the value means

to_schema (CHARACTER VARYING, nullable)

the to_schema of a row of this rule, materialized into intent_field_reference_step_hop.to_schema, whose comment carries what the value means

to_table (CHARACTER VARYING, nullable)

the to_table of a row of this rule, materialized into intent_field_reference_step_hop.to_table, whose comment carries what the value means

constraint_name (CHARACTER VARYING, nullable)

the constraint_name of a row of this rule, materialized into intent_field_reference_step_hop.constraint_name, whose comment carries what the value means

fk_on_from (BOOLEAN, nullable)

the fk_on_from of a row of this rule, materialized into intent_field_reference_step_hop.fk_on_from, whose comment carries what the value means

intent_field_reference_step_target (view)

Where each element of a field’s @reference path actually lands: the hop view walked from the enclosing type’s table binding, one element at a time, so a row exists only for an element the chain can be shown to reach. Recursive because the arms are sequential and nothing else about them is: an element’s departure is the previous element’s arrival, and only the first element’s departure is known without walking, being the type’s own binding. The seed reads intent_resolved_type_binding and not the @table population alone: what the walk needs is a table for the enclosing type, and a type standing for a routine chain’s result has one whether or not the author also wrote the directive, so seeding from the directive would leave a path departing such a type reaching nothing for exactly the schemas that stop restating the routine as a @table. Two consequences worth stating, both deliberate. An element that resolves to nothing ends the chain, so a path whose second element is fine but whose first names an unknown key contributes no rows at all rather than a row starting from nowhere; that is the walk’s own behaviour and the reason absence here means "not reached", never "resolves to nothing in particular". And an element carrying neither key nor table is not a hop this view knows: a condition-only element takes its target from the condition method’s Java return type, and an omitted path is foreign-key discovery between a parent and a child type, both resolutions this view does not perform and neither of which should be mistaken for its silence. Terminal-element readers project the maximum position per application; the chain has no separate terminal relation because one would be a reduction over this view with a single reader.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the hop view

type_name (CHARACTER VARYING, nullable)

the type owning the field the @reference is applied to; also the type whose binding started the chain

field_name (CHARACTER VARYING, nullable)

the field the @reference is applied to

ordinal (INTEGER, nullable)

the owning @reference application’s ordinal, since the directive is repeatable

position (INTEGER, nullable)

the element’s 0-based position within its application’s path; positions are contiguous from 0 up to wherever the chain stopped

via (CHARACTER VARYING, nullable)

which arm resolved the element, as on the hop view: KEY, TABLE or NAME_MATCH

key_matched_by (CHARACTER VARYING, nullable)

for a KEY element, the namespace that answered; NULL on a TABLE or NAME_MATCH element. As on the hop view

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition; the type’s bound table at position 0, the previous element’s arrival after that

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name. At the path’s last position this is the table a @field(name:) on the same field resolves its column against

constraint_name (CHARACTER VARYING, nullable)

the foreign key this element joins on, named or discovered; NULL on a NAME_MATCH element, as on the hop view

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key; the element’s direction. NULL on a NAME_MATCH element, as on the hop view

targets (INTEGER, nullable)

how many distinct tables this element reaches, this row’s arrival being one of them; 1 where the destination is certain. Separate from candidates because the two arities answer different questions and genuinely differ: a table element with three foreign keys connecting the two tables reaches one table by three routes, so a reader that only needs the destination can trust it while a reader that has to render the join cannot

candidates (INTEGER, nullable)

how many rows this element resolved to, counting routes and not just destinations; 1 is the walk’s requirement for an expressible hop, and a larger number is what its own "which foreign key did you mean" rejection counts

intent_field_routine_method (view)

The generated call surface a @routine application names: graphitron_routine resolved through intent_spelled_table and onto sql_routine, one row per call surface the application matches. The sibling of intent_field_producer_method, and the same shape for the same reason: an authored coordinate reaching into a census is a use-keyed resolution over a source-keyed relation, and it states the resolution alone. How a written name meets the catalog is the spelling view’s rule, stated once there; that a @routine(name:) resolves under it is that view’s own claim, jOOQ modelling a function result as a catalog table. Keyed on the application rather than the field, because @routine is repeatable and the ordinal is what tells two applications on one field apart, in the written order the table chain interleaves them in. No table_type filter: a spelling naming a stored table resolves on the spelling view and then matches no row here, so the join says "not a callable" without restating what sql_table.table_type means. Absence has three causes and the joins separate them: no spelled-table row means the name matched no catalog object at all, a spelled-table row with no routine row means the object it matched is not callable, and a routine whose generated model exposes no call surface is excluded here, because this relation is the call surface and naming a class that does not exist would be a worse answer than naming nothing. Ambiguity is rows and never a decline, as on intent_bound_table.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphitron_routine

type_name (CHARACTER VARYING, nullable)

the applying field’s owning type

field_name (CHARACTER VARYING, nullable)

the applying field’s name within the owning type

ordinal (INTEGER, nullable)

the @routine application’s own ordinal, carried from graphitron_routine; the fourth key part, because a field may carry several applications and each resolves on its own

source_name (CHARACTER VARYING, nullable)

the resolved routine’s catalog partition, the first column of the sql_routine key this row names; the partition the graph reached through the spelling view’s own scoping

table_schema (CHARACTER VARYING, nullable)

the resolved routine’s SQL schema; what tells two candidates of one spelling apart

routine_name (CHARACTER VARYING, nullable)

the resolved routine’s SQL name. With the two columns above this is sql_routine’s full key

class_name (CHARACTER VARYING, nullable)

the generated Routines class carrying the call surface, from sql_routine.routines_class_fqn. Never null: a routine the generated model exposes none for has no row here at all

method_name (CHARACTER VARYING, nullable)

the Routines-class method an emitted FROM clause calls, from sql_routine.routines_method_name. Never null, on class_name’s terms, the two being null together in the census

parameters (INTEGER, nullable)

how many IN parameters that method takes: the count of sql_routine_parameter rows for the routine, which is the call surface’s arity. A fact about the generated method, so it is the answer whether or not the consumer’s generated sources were ever scanned as a classpath entry, which they ordinarily are not. 0 is an honest arity here and not a fallback, a routine with no parameters and one whose surface the model does not expose being separated by the row’s existence rather than by this column

candidates (INTEGER, nullable)

how many call surfaces this one application resolves to, this row being one of them; 1 on an unambiguous one. Partitioned by the application, as intent_field_producer_method partitions by the reference, and stated as a column on intent_bound_table.candidates' terms: whether the resolution is unique is what decides the reading

intent_field_scope_table

Which table a field’s own generated SQL binds against: the table the field selects from, the table a predicate built at this coordinate correlates on, and the table a @nodeId or @reference path written here departs from. Stated at the field’s own grain rather than at an argument’s, which is the correction this relation is: the rule lived inside intent_argument_scope_table, keyed per argument, where nothing about it was ever an argument’s. The coordinate and the table together are the grain, one row where one table answers and one row per table where several do, which is not a widening for its own sake but what the polymorphic arm below states: a field returning a multi-table container is several statements, one per branch, and each is rooted in its own table. Three ranked rungs and one arm disjoint from all of them. The field’s navigated type’s own binding is the ordinary case, read through intent_field_navigated_type so a connection field navigates as its element type rather than as its edge wrapper, whichever of the two ways that connection came to exist. Below it the write payload’s data channel, which is what answers where a DML mutation returns a carrier the author wrote to wrap the written row: the payload type binds nothing of its own, and the table the coordinate’s statement is rooted in is the one that carrier’s single data channel binds. It is read off intent_carrier_data_field rather than rederived, so the payload scan is applied where it is stated; demanding one channel of element kind TABLE is that relation’s own arity refusal transcribed, and it is also what makes the rest of the scan moot here, a payload with one bound channel having no second channel to be unrecognized and no ID channel to refuse. Below that a @mutation(table:) spelling, which is what answers where the return names no table at all: a delete surface returns a scalar or a status type and its arguments still bind against the table the mutation names. The rungs are a precedence and not a union, because a mutation whose payload type is itself bound has both and the named type is the one the classifier reads; DENSE_RANK over the rungs rather than ROW_NUMBER, so a winning rung keeps every row it answered with and an ambiguity stays visible as rows instead of being resolved by window order. Both rungs demand an unambiguous binding, on intent_field_reference_discovery’s terms: a table this field’s content binds against is a table a predicate is emitted on, and two candidate tables are two different predicates, so a pair that is not certain is not the pair the classifier would have had in hand. Beside the two rungs and outside their window sits the participant arm, the distinct tables of intent_field_participant_scope_table under the basis PARTICIPANT_TABLE. It is unioned in rather than ranked as a third rung because it contends with neither: its own precondition is that the field’s named type binds no table at all, which is what the upper rung requires it to have, and it excludes the field carrying a resolving @mutation(table:) spelling, which is what the lower rung reads. Calling it a rung would state a precedence the site does not have. It is distinct on the table because the grain here is the table while that relation’s is the participant, so two participants of one field backed by one table are one statement’s root and one row; a consumer that needs to know which participant reads that relation directly, and one minting a per-participant unit name must, the generated condition method being named after the participant. A field whose named type binds nothing, whose named type is no polymorphic container over bound members, and which carries no @mutation therefore has no row here, and that absence is the ordinary case for every field that reads no table at all. The middle clause of that sentence is the one this relation once got wrong: the participant population was missing outright, so a multi-table polymorphic root read tables, plural, and had no row, and every reader below inherited a silence none of them owned. The payload rung closed a second silence of the same kind, and it was the larger one. A @mutation(typeName: INSERT) or UPDATE field returning a carrier payload and naming no table had no row here, so its arguments had no scope, so the input fields under them had no resolving table, and the whole input-field family below that, the column scope, the column match, the filter role, the carrier role and the decode’s departure, was blank at exactly the coordinates a write surface is about. It read as a schema holding no such mutations rather than as a rule that could not answer them, and what hid it is that an input type is usually shared: an input reached both from a payload-returning coordinate and from a directly-returning one resolves its fields against the table the second one supplies, so the fields look classified while the mutation stays invisible. The rung is gated on the two verbs whose write target the classifier derives from the return, INSERT and UPDATE, which is the set the resolver itself holds; a DELETE cannot return the deleted row’s @table type, so its carrier’s data channel is an encoded key rather than a row and the table it writes is the rung below’s to state. That rung is also why this relation and the argument-grain fan-out beneath it are declared after the carrier family rather than beside the bindings they read: intent_carrier_data_field reaches the backing closure, and the order here is a dependency rather than a reading order. Nothing here says anything is column-shaped: this relation answers where a binding would land if there is one, and which arguments or names carry such content is each consumer’s own question. Not to be confused with intent_field_column_scope, whose name is close and whose question is not: that relation answers where a column name written at this site resolves, which for a leaf field is its own parent’s binding, where this relation answers where the field’s own statement is rooted. The two agree on an object-typed field and disagree on every scalar one, and they carry different guards for that reason. Two consumers read this. intent_argument_scope_table is this relation fanned out over the field’s arguments and adds nothing else, which is what makes the fan-out its whole content rather than a rule of its own. And the condition membership fold reads it at this grain, which is why the grain had to be corrected before that fold could exist: a @condition on a field with no arguments has a table to filter and no argument to carry it, and a @condition on a multi-table polymorphic root has one table to filter per branch and one generated method per branch to carry it. The upper rung reads intent_field_navigated_type, which is the projected shape two earlier essays on this relation argued against and one of them measured at two orders of magnitude. Both were true when written and neither is now, and what changed is worth stating because it is the same lever twice. The hazard was that joining a derived relation onto a written expression makes H2 evaluate that relation once per driving row; registering intent_resolved_type_binding removed it, the far side of the join becoming a table with nothing to re-evaluate. The projection then became possible and was still refused, because with the binding a column rather than an expression H2 stopped probing that table and started scanning it, and DerivedReadCostTest fails a registration that costs another reader more than it saves. An index on the binding, ix_resolved_type_binding_type, is what closed that: it is the probe every reader of that relation makes, the registration shipped without one, and an unkeyed table is not a faster shape but a differently shaped one. With the index the rung measures under a millisecond on the sakila example schema at 928 fields, returning 233 rows where the expression shape returned 227, the six extra being the coordinates that return a connection type the author declared and that the expression shape could not see at all. This relation as a whole costs 60 milliseconds and the participant arm is essentially all of it; its own comment carries that arm’s figures and the three shapes tried for it. Materialized: this relation is a table refilled from intent_field_scope_table_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from graphql_field on the upper rung and the participant arm and from graphitron_mutation on the two mutation rungs

type_name (CHARACTER VARYING, not null)

the type owning the field

field_name (CHARACTER VARYING, not null)

the field whose scope this row states; with the two columns above and the table below, the grain

basis (CHARACTER VARYING, not null)

which rule answered, in a closed vocabulary of four: NAMED_TYPE_TABLE from the field’s named type’s own binding, PAYLOAD_TABLE from the single data channel of a DML write’s carrier payload where the payload itself binds nothing, MUTATION_TABLE from the @mutation(table:) spelling where neither of those answers, PARTICIPANT_TABLE from one branch of a named type that is a polymorphic container binding no table of its own. The first three are ranked rungs and the fourth is disjoint from all of them; which of them a row carries is therefore not only provenance but the fork a consumer takes, PARTICIPANT_TABLE being exactly where the coordinate is several statements rather than one. What lets a test pin which rule fired rather than only that a table came out; a reader wanting one of them filters on it and owns having chosen

table_source_name (CHARACTER VARYING, not null)

the scope table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, not null)

the scope table’s SQL schema

table_name (CHARACTER VARYING, not null)

the scope table’s SQL name; with the two columns above this is sql_table’s full key, so the table’s own columns and constraints are one join away

intent_field_scope_table_live (view)

This states the rule and is evaluated on demand. The canonical name intent_field_scope_table beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_field_scope_table.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_field_scope_table.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_field_scope_table.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_field_scope_table.field_name, whose comment carries what the value means

basis (CHARACTER VARYING, nullable)

the basis of a row of this rule, materialized into intent_field_scope_table.basis, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_field_scope_table.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_field_scope_table.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_field_scope_table.table_name, whose comment carries what the value means

intent_field_separate_fetch (view)

Which fields are fetched by a statement of their own rather than projected out of the enclosing SELECT, one rule literal per arm. The question a schema author asks about round-trips: a field with no row here that resolves against its parent’s table costs nothing beyond the parent’s own statement, while a field with one is a second trip to the database. The two marker arms are the delivery-forcing union the table-backed child arm reads (@splitQuery defers the fetch through a DataLoader; @tenantFanOut forces the same boundary because a fanned child runs once per tenant and cannot join into a parent statement running on one source), stated as separate rules rather than one DELIVERY_MARKER because which marker forced the split is what an author reads and the two are written for different reasons. The service arm is the non-root @service contract: the service fetches independently of the parent’s SELECT, which is why the split is required rather than optional there. The root arm is every field of a bound root operation type, whose fetch is the operation’s own entry point and never a projection of anything; keyed by the root operation binding rather than the conventional names, so it states the intended rule the way the demand rules do, today’s walk dispatching on the literal names being the same known difference recorded there. The record-handed-parent arm is the implicit split, the one no author writes: a field of a type the backing closure grounds on a class, naming a type of its own that is bound to a table. There is no enclosing statement for such a field to be projected out of, the parent’s value being a Java object a producer handed back rather than a row of a running select, so the child’s table is a trip of its own. It reads intent_type_backing_class rather than the coalesced intent_type_backing, and anti-joins the parent’s own @table binding away, because a type both populations answer is one the walk reads as a table row and never as a handed object; that precedence is the one intent_type_backing’s comment records, so transcribing it is the same reading rather than a new opinion. The anti-join is over intent_bound_table and not over the coalesced view’s table arm, because what makes a parent a table row is its binding, whether or not jOOQ generated a record class for the table the binding names. Both joins over that binding stay on the @table population rather than moving to intent_resolved_type_binding as the navigation relations did, and that is a deliberate hold rather than an oversight: a type standing for a @routine chain’s result is handed to its children by the routine’s own statement, so whether such a parent is a table row or a handed row is the same precedence question this arm exists to state, and answering it by substituting the relation would decide it in passing. The two joins move together when it is settled. The parent’s kind is guarded and the child’s is not: the closure holds input objects beside objects and an input coordinate is not a fetch, while on the child side @table on an input object is unreachable from an object’s field to begin with. The literal is the walk’s own trigger name, so one population keeps one word wherever it is stated; record there means a producer-handed domain object, which this schema calls a class backing. Two readings depart from today’s walk and both are the intended rule. An ambiguously bound child splits here where the walk mints no table-backed verdict for it at all, since an ambiguous binding is contested rather than projected, and the split is what an editor can say about a schema mid-edit; a reader wanting the walk’s reading filters on intent_bound_table.candidates the way every other reader of that arity does. A @table interface child splits at either cardinality where the walk inlines the single-valued one, its discriminated-interface arm running before its record-handed one. Two populations stay absent, which is why absence is still not the complement’s claim: a child reached through a connection wrapper, no relation naming a connection’s element type, and the polymorphic fan-in, where a list-valued interface or union child with a table-bound participant batches through a DataLoader. A reader may say a field with a row is separately fetched, and may not say a field without one is inlined.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried through from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the separately fetched field’s owning type

field_name (CHARACTER VARYING, nullable)

the separately fetched field’s name within the owning type

rule (CHARACTER VARYING, nullable)

why the fetch is its own; a closed vocabulary (SPLIT_QUERY, TENANT_FAN_OUT, SERVICE, ROOT_OPERATION, RECORD_HANDED_PARENT) the reading side decodes into a typed value. A coordinate several rules cover is several rows, the arity being the answer rather than a precedence this view picks; each rule’s witnesses live one join away in the arm’s base relation, so no arm’s witness columns go nullable on the others

intent_foreign_key_column_pair (view)

What a foreign key equates: one row per position, the key’s own column beside the column it references. The join condition every reader that renders or reasons about a foreign key needs, and a derivation rather than a capture because the census records the two constraints' column lists separately and the pairing between them is positional. Positional is the whole content of this relation and it is SQL’s own rule rather than a convention adopted here: a foreign key’s Nth column references the Nth column of the constraint it points at, which is why sql_constraint_column carries a position at all and why nothing else has to be matched on a name. Both sides are joined on their own constraint’s full key, so a constraint name two schemas or two classpath entries both declare pairs within its own table and never across, which is the collision the endpoint triples exist to prevent. A key whose referenced constraint has fewer columns than it declares pairs only the positions both sides hold, and that is a malformed catalog rather than a shape to model: the census would have to have recorded a key SQL could not have created. No arity is exposed beside the pairs, the position being dense from zero on both sides, so a reader wanting the width counts rows. Nothing here is specific to any one consumer’s question, which is why it sits with the catalog derivations and not beside the relation that first needed it: the @nodeId lift is its first reader and a rendered join is its obvious second.

Columns
source_name (CHARACTER VARYING, nullable)

the declaring table’s catalog partition, as on sql_referential_constraint

table_schema (CHARACTER VARYING, nullable)

the declaring table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the declaring table’s SQL name: the table the foreign key sits on, which is the child end of the relationship

constraint_name (CHARACTER VARYING, nullable)

the foreign key’s name under the declaring table, completing sql_referential_constraint’s key with the three columns above

position (INTEGER, nullable)

0-based position within the key, dense from zero, shared by both sides of the pair; the order a tuple predicate over the key has to preserve

column_name (CHARACTER VARYING, nullable)

the key’s own column at this position, on the declaring table. The catalog’s own spelling, so a reader matching it against an authored one folds the authored side

referenced_source_name (CHARACTER VARYING, nullable)

the referenced table’s catalog partition

referenced_schema (CHARACTER VARYING, nullable)

the referenced table’s SQL schema

referenced_table (CHARACTER VARYING, nullable)

the referenced table’s SQL name: the parent end of the relationship, equal to the declaring table on a self-referencing key

referenced_column_name (CHARACTER VARYING, nullable)

the referenced constraint’s column at this position, on the referenced table; the other half of the equality this row states

intent_inferred_node_type (view)

A type nobody wrote @node on that is a node anyway: an @table binding, an implements Node, and a bound table whose generated class publishes well-formed node-identity metadata. The inferred half of nodehood, kept a relation of its own rather than a tagged arm of the membership reduction, per the provenance rule the schema applies throughout: authored and inferred values reached by independent rules live in separate relations coalesced by a view, and a tag column no reader forks on is inventory. What earns this one its place independently of that reduction is the witness columns, which say which table’s metadata made the type a node; a reader asking that question joins instead of re-deriving the binding. Well-formedness is the conjunction intent_node_metadata_defect’s own comment states, a metadata row with no defect rows for it, and not the anti-join alone: a table publishing nothing at all also has no defect rows, and that table is not a node. The membership is a cross-corpus join, which is the licensed shape for a derivation precisely because no crawler may perform one. Its binding is intent_bound_table, the @table arm alone, deliberately and not the intent_resolved_type_binding reduction the sibling spelling below stands on: nodehood demands a written @table, so a type whose only binding is a routine chain’s return is not a node however well-formed that table’s metadata is. Its sibling spelling is intent_resolved_node_key_column’s JOOQ_METADATA tier, which carries the same well-formed-metadata conjunction on that other stand; the duplication is stated rather than latent, so a reader who finds one finds the pair, and folding the conjunction into a relation of its own on sql_table’s key is the follow-on neither view performs on its own. Standing on intent_bound_table it inherits intent_spelled_table’s window function, so an outer predicate cannot prune it: a caller filtering on one type still resolves every spelling in the graph.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the binding

type_name (CHARACTER VARYING, nullable)

the type this row infers nodehood for; keyed with the graph, one row per inferred node type

table_source_name (CHARACTER VARYING, nullable)

the metadata-publishing table’s catalog partition, the first column of the sql_table key this row names; a witness, so the reader that asks which table made this a node joins rather than re-deriving the binding

table_schema (CHARACTER VARYING, nullable)

the metadata-publishing table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the metadata-publishing table’s SQL name. With the two columns above this is sql_table’s full key, and the sql_node_metadata row this inference read sits on that same key

intent_input_field_carrier_role (view)

What a column-bearing input field points at, which is what decides whether its value can be compared on the table it was classified against and, where it can, whether those columns are that row’s own identity or a pointer at another row. The sibling of intent_input_field_filter_role one question over: that relation says which rule resolves the field’s columns, this one says what the thing at the end of that resolution is. Both are needed and neither implies the other, a name match and a node id alike being able to land on own columns or on a foreign key’s. The population is that sibling’s two column-resolving roles and nothing else, which is why this relation is driven from it rather than from the column scope beneath it: a scope answers where a name would resolve if one is written, and it answers for every input field, so a nesting field whose name happens to match a column of the table has a scope like any other. Only the ordered fork one rung up knows that such a field is a nesting and not a carrier, and a relation reading the scope directly would name a carrier at three sites that carry nothing. A closed vocabulary of four. OWN_COLUMNS is a site resolving on the table it was handed, which is the plain field, the same-table node id carrying no reference, and the inert empty reference path that falls back to the field’s own table; its columns are this row’s identity wherever they are in a key, so a consumer partitioning them may not split one such field across a key boundary. SELF_FK and CROSS_TABLE_FK are the two shapes of a node-id reference whose decoded key lands on this table’s own columns: the first names a foreign key back to the classifying table, so the columns point at a sibling row and are never this row’s identity however the key falls; the second points at another table, and its lifted columns can legitimately include this row’s identity, which is why it is the one carrier a consumer may partition per column rather than whole. REMOTE is everything else, and it is a rejection’s population rather than a fourth way to contribute: the value reaches its row only through a join, so there is nothing local to compare it against, and every write rail refuses the shape at its own gate. Several distinct causes collapse into it deliberately, because the consumer’s answer is the same for all of them and splitting them would invite a reader to treat one as usable: a plain reference with a non-empty path, whose predicate goes through an EXISTS; a node-id reference any position of whose key lands on no column of this table, whether because the key it followed references other columns or because the chain crossed a table that translated one; and a node id whose named type binds no table this relation can reach, where nothing was decoded to land anywhere. How the node-id arms are decided is worth stating, because the obvious spelling is wrong and was written first. The question is not which foreign keys of this table could reach the node type and whether one of them carries the key directly; it is where the decode this site actually performs put each position, which is intent_node_id_decode_column’s subject and is stated there per position. Every position landing on a column of the departing table is a local tuple and anything short of that is remote, counted here as two aggregates over that relation rather than re-derived, so this relation and the destination reduction beside it cannot disagree about what local means. The per-key spelling that stood here first is what that replaced. It asked whether some foreign key from this table to the node type lifted the node key directly, which is a fact about the catalog rather than about this site, and it was wrong in both directions: a same-table reference short-circuited to SELF_FK without asking the question at all, so a self-FK through a key referencing anything but the node key read as usable when the resolver refuses it; and where a table declares two keys to one target the answer was whichever of them lifted, rather than the one the author’s @reference names. What this relation does not say is which columns, or whether they fall in a key. Those are the match relation’s and the catalog’s, joined through this row; the carrier’s kind is a property of the reference and the same at every key it might be measured against, so folding a key membership in here would make the grain a key and duplicate every row per candidate. Absence is an input field whose site resolves to no column at all, which is the nesting field, the unbound one and the condition-owned one, none of which is a carrier and each of which the sibling relation already names, together with every site that relation declines outright.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the column scope

type_name (CHARACTER VARYING, nullable)

the input object type the field is declared on

field_name (CHARACTER VARYING, nullable)

the input field’s name within its container

resolving_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table the site was classified against; part of the grain, so a shared input type reached from two tables gets a row for each

resolving_schema (CHARACTER VARYING, nullable)

the classifying table’s SQL schema; part of the grain, as above

resolving_table (CHARACTER VARYING, nullable)

the classifying table’s SQL name; with the two coordinate columns and the two columns above, the grain

carrier_role (CHARACTER VARYING, nullable)

what the carrier points at: OWN_COLUMNS, SELF_FK, CROSS_TABLE_FK or REMOTE, the four the classifier can answer. A closed vocabulary, and a fifth carrier shape is a new value here rather than a silence

intent_input_field_column_match (view)

Which column an input field’s own name resolves to on the table its site navigates to: the column a predicate or an assignment built from that field names. The input-field counterpart of intent_argument_column_match, and everything that relation argues about not being a claim holds here for the same reason: no classifier vocabulary reaches an input field, and what such a field gets from a resolved column is a binding and not a kind, so these rows carry no classifier column and nothing reduces them. The field’s named type has kind SCALAR or ENUM, which is the classifier’s own structure rather than an addition: an input-object-typed field is a nesting the walk descends into and resolves at the fields below it, so a name match against the container itself would be a row no consumer asked for. The site resolves against exactly one table, which is intent_input_field_column_scope’s resolution, so every decline that relation makes is a silence here and this view adds none of its own. The effective name is the @field(name:) binding where one was written, else the field name, which is the classifier’s own COALESCE, and the same directive relation answers it here as at an output field, an input field being a graphql_field row like any other. The match is two-tier, the generated Java name before the SQL name, both case-insensitive, collapsed to the first match in tier-then-ordinal order. The scope drives the join, which is load-bearing rather than stylistic on the measurement intent_column_match_claim’s comment carries: reading the scope from underneath the field relation would cost the whole scope once per candidate field. What this relation does not answer is what the resolved column is for. A column reached from a read surface’s filter argument is a predicate and one reached from a mutation’s payload is an assignment or a key, and nothing on this row tells those apart, the classifier deciding it from the consuming site rather than from the input field. Absence is where a written name reaches no column on the resolved table, which is the classifier’s unbound-field carrier, and it is equally the ordinary answer for a field whose content is not column-shaped at all: an ID field standing for a node id resolves its columns from the node key and not from its name, and a field carrying a rejected @notGenerated or @lookupKey application contributes nothing at all. Nothing here tells those apart either, and what would is a role relation over this one rather than a column on it.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the scope

type_name (CHARACTER VARYING, nullable)

the input object type the field is declared on

field_name (CHARACTER VARYING, nullable)

the input field whose name this row resolves

resolving_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table the site was classified against; carried from the scope, where it is part of the grain and here too

resolving_schema (CHARACTER VARYING, nullable)

the classifying table’s SQL schema; part of the grain, as above

resolving_table (CHARACTER VARYING, nullable)

the classifying table’s SQL name; with the two coordinate columns and the two columns above, the grain

matched_name (CHARACTER VARYING, nullable)

the effective name that matched: the @field(name:) binding where one was written, else the input field’s own name

matched_by (CHARACTER VARYING, nullable)

which tier answered, in a closed vocabulary of two: JOOQ_NAME (the generated Java name) or SQL_NAME. The generated name is preferred where both match, which is the classifier’s order

table_source_name (CHARACTER VARYING, nullable)

witness: the resolved table’s catalog partition. Which navigation reached it is intent_input_field_column_scope’s basis, and a consumer emitting the binding needs both

table_schema (CHARACTER VARYING, nullable)

witness: the resolved table’s SQL schema

table_name (CHARACTER VARYING, nullable)

witness: the resolved table’s SQL name

column_name (CHARACTER VARYING, nullable)

the resolved column’s SQL name on that table; with the three witness columns above, sql_column’s full key

source_name (CHARACTER VARYING, nullable)

the input field’s own declaration file; the position a diagnostic would carry

source_line (INTEGER, nullable)

source line of the input field declaration, 1-based

source_column (INTEGER, nullable)

source column of the input field declaration, 1-based

intent_input_field_column_scope (view)

Which table the column name written at an input field resolves against: the input-field twin of intent_argument_column_scope and intent_field_column_scope, and a third relation for the reason the third walk is a third walk. The departure differs and here it is not even a function of the coordinate, so the resolving table is part of the key and the same input field carries one row per table it is classified against. Two rules, disjoint rather than ranked, so this is a plain union with no windowed collapse over it and it carries the one-row-per-site property both twins stand on. An authored @reference path resolves to its terminal element’s table, demanding the terminal reach exactly one table rather than exactly one row, so an element joining two tables by three keys still names its destination; the DISTINCT over a projection keeping only the table is what collapses several routes to one destination. An input field with no path element resolves in the table it was handed, read from intent_input_field_resolving_table rather than restated, so the two spellings of that departure cannot drift. Repetition is a conflict and not a chain, as at the argument site and unlike at the output-field site: ordered composition has no meaning on an input field, the resolver rejects a second application outright, and a site carrying two has no row here under either rule. That second demand is on the applications and not on their elements, so an author writing an empty @reference(path: []) beside a real one has no row here, and an author writing one empty application alone has the resolving-table row, which is the bare predicate a directive-less field would have produced and is what the resolver gives that site. Nothing here reads the classifier’s ordered fork. A @notGenerated or @lookupKey application, a @nodeId decode, a nested input object and a plain name all have a scope, and which of them the classifier actually resolves the site as is a role question one rung up; this relation answers where a name would resolve if one is written, which is intent_argument_column_scope’s stance at its own site. Its consumer is intent_input_field_column_match, which asks which column the name reaches.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from both rules' base relations

type_name (CHARACTER VARYING, nullable)

the input object type the field is declared on. Not the type whose binding started any navigation, an input object having none, which is the difference from the output-field twin where the two are one

field_name (CHARACTER VARYING, nullable)

the input field whose site this row resolves

resolving_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table the site was classified against; part of the grain, so a shared input type reached from two tables gets a row for each

resolving_schema (CHARACTER VARYING, nullable)

the classifying table’s SQL schema; part of the grain, as above

resolving_table (CHARACTER VARYING, nullable)

the classifying table’s SQL name; with the two coordinate columns and the two columns above, the grain. Equal to the resolved table on the RESOLVING_TABLE rule and the walk’s departure on the other

basis (CHARACTER VARYING, nullable)

which rule resolved this site, in a closed vocabulary of two disjoint rules: PATH_TERMINAL (an authored input-field @reference path’s terminal element), RESOLVING_TABLE (no path element written, the table the classifier was handed). Also the fork a predicate binding takes, PATH_TERMINAL being exactly the case where the resolved table is not the one the consuming field already selects from

table_source_name (CHARACTER VARYING, nullable)

the resolved table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the resolved table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the resolved table’s SQL name. With the two columns above this is sql_table’s full key, so the table’s columns are one join away

intent_input_field_filter_role

Which rule resolves what one input field contributes at the site that reaches it. The input-field counterpart of intent_argument_filter_role, and the relation a consumer assembling a generated predicate or a generated assignment out of an input surface reads before it reads any of the resolution relations under it, because what it needs first is which of them applies. The grain differs from the argument relation’s, and that is the first thing to know about it. An argument’s role is a function of the argument. An input field’s is a function of the field and the table it was classified against, because two arms of the fork ask the catalog a question about that table: whether the written name reaches a column on it, and whether it backs exactly one node type. So the resolving table is part of the key here exactly as it is on the three resolution relations below, and the same input field reached under two arguments whose fields select from different tables carries two rows and can carry two different roles. The switch is an ordered fork rather than a set of disjoint tests, so this is a ranked collapse and not a union: the two retired directive applications first, then an authored @nodeId, then a @reference path, then a nested input object, then the implicit node id, then the condition-owned carrier, then the name match, then the unbound carrier. Ranking rather than unioning is what keeps a field carrying two of these from surfacing twice, and the order is the classifier’s own rather than a precedence this relation invented. Three of the arms ask whether the field’s name reaches a column, so each of them names intent_input_field_column_match, which H2 inlines with no common-subexpression elimination. Folding those three into one pass over the sites, with the match left-joined once and the fork written as an ordered CASE over its columns, was written and measured and is worse: on the sakila example schema, 917 fields and 267 arguments, the ranked arms take sixteen milliseconds and 9592 rows visited where the one-pass shape takes 166 and 10822, both answering the same 107 rows. The arms are cheap for a reason a scan count does not show, which is that each names the match under a driver of its own. The name-match arm reads it once and sequentially, and the other two correlate into it over the small populations of @reference-bearing and node-id-instructed fields, where the single pass joins it once per site with no index to reach it by. The read-cost gate’s scaled fixture said the opposite of this, its units making every input field carry a @reference and so making both correlated arms unselective; when a synthetic fixture and the shipped schema disagree by an order of magnitude, the shipped schema is the measurement. What the roles mean. NODE_ID means the columns come from a resolved node key rather than from a name, and it covers both readings the store already carries, the authored @nodeId and the implicit one at an ID field literally named id whose resolving table backs exactly one node type. Both are read off intent_node_id_instruction, which has already applied the node-type resolution and every decline it makes; what this relation adds is the wiring that relation deliberately does not state, which at this site is two exits. A column of the field’s own name on the resolving table shadows the implicit reading into a rejection, and it is tested ahead of the column lookup so that a real column of that name is a rejection rather than a contest either reading wins. A @field(name:) binding suppresses the implicit reading too, and here that is a fall-through to the name match rather than the rejection the argument site gives it: at an argument a binding beside an implicit node id names two binding axes at once and the site resolves to nothing, and at an input field the binding simply renames what the column lookup looks for. Beside an authored @nodeId a binding is neither of those, the resolver never consulting it. NESTING means the contribution is the nested input type’s own fields, resolved at their coordinates and against this same table, so a reader following it changes coordinate without changing table. That last clause is why the resolving table is stable down a whole tree: the nesting arm descends with the table it was handed, and a @table application on an input object is captured and ignored. NAME_MATCHED means the contribution names the column intent_input_field_column_match resolved, and it covers the @reference-pathed field and the plain one alike, the column resolution already telling them apart by its scope’s basis. CONDITION_OWNED means @condition(override: true) on the field: the method owns the whole contribution and no column is recorded, which is the classifier’s one carrier reached from both sides of the column lookup, the column having resolved and the column having missed. It is deliberately ranked under the four arms above it, because a node-id, @reference-pathed or nested field carrying override: true still takes its own arm and carries the condition alongside; only a plain scalar field reaches the fork where the override decides the carrier. UNBOUND is where this relation departs from its argument-grain counterpart. There, absence is uniformly a rejection’s population. Here the classifier has a resolved carrier for a field whose name reaches no column, so a site that contributes nothing of its own has a role rather than a silence, and what that role means is a question one rung up: with no authored @condition the carrier is cascade-dependent and the consumer’s use-keyed walk decides it, and with an authored @condition(override: false) the pair is exactly the located rejection the validator mints, a composing condition having no implicit predicate left to compose with. That pair, role UNBOUND and authored_condition true, is a rejection’s population stated as two columns instead of as an absence, which is the point of giving the carrier a name. Absence proper is the rejection population, and every site in it is a rejection rather than a field that quietly contributes nothing: a @notGenerated or @lookupKey application, both retired at this site and both rejected outright rather than ignored; a repeated or unresolvable @reference, repetition being a conflict here and not a chain; an implicit node id shadowed by a column of that name; an ID field named id whose resolving table backs more than one node type, which the instruction relation declines by requiring a single candidate and which this relation therefore has to state for itself, so that a later arm cannot claim the site the classifier rejected; and an authored @nodeId whose target resolves to no node type, which is a rejection here and not a fall-through, the classifier entering that arm on the directive and the ID type alone and never returning to the column lookup below it. What the decode then does with a target that did resolve is the decode relations' answer rather than this one’s. Two facts about a contribution are deliberately not here, both because they are occurrence-grain and both already stated at that grain. The enclosing @condition(override: true) cascade is intent_input_occurrence_override’s, keyed by occurrence path, because one input field reached under two paths can sit inside an override on one and not on the other. The circular-nesting cut is intent_input_occurrence_path’s, for the same reason: a field closing a cycle on one path is an ordinary nesting on another. That cut is the one arm of the classifier’s fork that reads path state rather than the definition and the table, and so the one arm this relation cannot transcribe; a reader walking occurrences holds the path already and joins both facts there, and a reader that only wants to know how a definition classifies against a table needs neither. What this relation does not state is the contribution itself. Which column, which comparison, which reach, and whether a resolved column is read as a predicate or written as an assignment are the resolution relations' answers and the consuming site’s, read through the role; putting them here would make this a filter-surface relation at the wrong grain, an input field being where the rule is chosen and not where the contribution is assembled. Materialized: this relation is a table refilled from intent_input_field_filter_role_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from graphql_field

type_name (CHARACTER VARYING, not null)

the input object type the field is declared on. Not the type whose binding started any navigation, an input object having none, which is the difference from the argument-grain counterpart where the owning type is the navigating one

field_name (CHARACTER VARYING, not null)

the input field this row classifies

resolving_source_name (CHARACTER VARYING, not null)

the catalog partition of the table the site was classified against; part of the grain, so a shared input type reached from two tables gets a row for each

resolving_schema (CHARACTER VARYING, not null)

the classifying table’s SQL schema; part of the grain, as above

resolving_table (CHARACTER VARYING, not null)

the classifying table’s SQL name; with the two coordinate columns and the two above it, the grain. One row per input field per table it is classified against, which is one row per classification the build actually performs

role (CHARACTER VARYING, not null)

which rule resolves the contribution: NODE_ID, NESTING, NAME_MATCHED, CONDITION_OWNED or UNBOUND, the winner of the ranked fork. A closed vocabulary, and a new classifier arm is a new value here rather than a silence

authored_condition (BOOLEAN, not null)

the field carries an authored @condition that composes with whatever the role contributes, which is every @condition except the override: true one CONDITION_OWNED already names. A modifier on the role and not a role, because the classifier attaches it inside four of the five arms rather than instead of them; the condition’s own identity is one join to graphitron_field_condition away

source_name (CHARACTER VARYING, not null)

the input field’s own declaration file; the position a diagnostic would carry

source_line (INTEGER, nullable)

source line of the input field declaration, 1-based

source_column (INTEGER, nullable)

source column of the input field declaration, 1-based

intent_input_field_filter_role_live (view)

This states the rule and is evaluated on demand. The canonical name intent_input_field_filter_role beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_input_field_filter_role.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_input_field_filter_role.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_input_field_filter_role.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_input_field_filter_role.field_name, whose comment carries what the value means

resolving_source_name (CHARACTER VARYING, nullable)

the resolving_source_name of a row of this rule, materialized into intent_input_field_filter_role.resolving_source_name, whose comment carries what the value means

resolving_schema (CHARACTER VARYING, nullable)

the resolving_schema of a row of this rule, materialized into intent_input_field_filter_role.resolving_schema, whose comment carries what the value means

resolving_table (CHARACTER VARYING, nullable)

the resolving_table of a row of this rule, materialized into intent_input_field_filter_role.resolving_table, whose comment carries what the value means

role (CHARACTER VARYING, nullable)

the role of a row of this rule, materialized into intent_input_field_filter_role.role, whose comment carries what the value means

authored_condition (BOOLEAN, nullable)

the authored_condition of a row of this rule, materialized into intent_input_field_filter_role.authored_condition, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_input_field_filter_role.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_input_field_filter_role.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_input_field_filter_role.source_column, whose comment carries what the value means

intent_input_field_reference_step_target (view)

Where each element of an input field’s @reference path actually lands: the same hop relation the two older walks read, chained from the table the input field is classified against. The third of three sibling walks and the third departure, which is the only thing that separates them. A field-site path departs from the enclosing type’s own binding; an argument-site path departs from the table the argument’s content binds against; an input-field path departs from the table its consuming field handed the expansion, because an input object type binds nothing and the walk would otherwise have no table to start from at all. That departure is intent_input_field_resolving_table’s whole subject and is read from it rather than restated. The hops are the field-site relation’s and not a fourth capture: an input field is a graphql_field row on an INPUT_OBJECT parent, so its @reference elements land in the same step relation an output field’s do and intent_field_reference_step_hop already enumerates their candidate joins. Only the seed differs, which is why this view exists and a fourth hop relation does not. The departure is part of the key here where the two siblings need no such column: their departure is a function of the coordinate, and this one’s is not, an input field reached under two arguments on different tables walking two different chains from one authored path. Everything the field-site sibling’s comment argues about the recursion holds unchanged: an element that resolves to nothing ends the chain, so absence means "not reached" and never "resolves to nothing in particular", and an element carrying neither key nor table is not a hop this view knows. Terminal-element readers project the maximum position per application, as there. One thing about this shape is worth a reader’s attention and is why the departure relation is a materialized table rather than the view it was written as. An anchor term is not evaluated once: H2 re-evaluates it alongside the recursive term, so a view named in an anchor is expanded on every iteration where the same join written as an ordinary query is planned once. Measured on the sakila example schema, the anchor join as a plain SELECT costs a millisecond whether the departure is a view or a table, and as this walk’s anchor it costs 39 milliseconds against the view and one against the table. The registration in meta_materialize carries the rest of those figures and is argued on this reader.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the hop relation

type_name (CHARACTER VARYING, nullable)

the input object type owning the field the @reference is applied to

field_name (CHARACTER VARYING, nullable)

the input field the @reference is applied to

resolving_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table this chain departed from; part of the key, unlike on either sibling walk, because an input field’s departure is its consuming site’s and not its own

resolving_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema; part of the key, as above

resolving_table (CHARACTER VARYING, nullable)

the departing table’s SQL name; part of the key, as above. Equal to from_table at position 0 and unrelated to it after that

ordinal (INTEGER, nullable)

the owning @reference application’s ordinal, since the directive is repeatable at capture; repetition on an input field is a conflict the resolver rejects, so a reader wanting the authored path counts applications rather than trusting this column to be zero

position (INTEGER, nullable)

the element’s 0-based position within its application’s path; positions are contiguous from 0 up to wherever the chain stopped

via (CHARACTER VARYING, nullable)

which arm resolved the element, as on the hop relation: KEY, TABLE or NAME_MATCH

key_matched_by (CHARACTER VARYING, nullable)

for a KEY element, the namespace that answered; NULL on a TABLE or NAME_MATCH element. As on the hop relation

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition for this element: the resolving table at position 0, the previous element’s arrival after that

from_schema (CHARACTER VARYING, nullable)

this element’s departing SQL schema

from_table (CHARACTER VARYING, nullable)

this element’s departing SQL table name

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition, first column of its sql_table key

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name. At the path’s last position this is the table the input field’s effective name resolves its column against

constraint_name (CHARACTER VARYING, nullable)

the foreign key this element joins on, named or discovered; NULL on a NAME_MATCH element, as on the hop relation

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key; the element’s direction. NULL on a NAME_MATCH element, as on the hop relation

targets (INTEGER, nullable)

how many distinct tables this element reaches, this row’s arrival being one of them; 1 where the destination is certain. Separate from candidates for the reason the sibling walks state: a reader that only needs the destination can trust a certain one where a reader that has to render the join cannot

candidates (INTEGER, nullable)

how many rows this element resolved to, counting routes and not just destinations; 1 is the walk’s requirement for an expressible hop

intent_input_field_resolving_table

Which table an input field is classified against, and the pair is the grain: an input field resolves against a table it is handed rather than one it owns, so the same input field reached under two arguments whose fields select from different tables is two rows here and two answers everywhere downstream. That is the whole reason this relation exists as its own name. The input-field classifier takes a resolving table from its caller and never re-roots it: the nesting arm descends into a nested input object carrying the same table down, and a @table application on an input object is captured and ignored, so every field in the tree under one argument shares that argument’s table. The table itself is the consuming field’s, read from intent_argument_scope_table because the classifier is handed the field’s own target table at both entry points, the read surface’s argument expansion and the write surface’s payload resolution. Where the consuming field returns a multi-table polymorphic container that answer is one table per branch, so the input field is classified once per branch and this relation carries a row for each, which is the classifier’s own shape: it lowers the whole filter surface once per participant, the expansion into an input type included. The pair being the grain is what makes that arrive without a rule here. Deliberately not the argument’s column scope, which is a different question one rung down: an argument-site @reference moves where the argument’s own name resolves and does not move where its input type’s fields resolve, the classifier passing the field’s table into the expansion either way. The domain is intent_input_occurrence_path’s, which already holds every input field any argument reaches and already stops where the classification walk stops, so this relation adds a table to that reach and nothing else; the DISTINCT is what collapses the several occurrences of one input field under one table back to the one classification the build performs. Absence is where no argument reaches the field, which is every input object no use site names, and where the reaching argument’s field binds no table at all, which is the ordinary case for an argument on a field that reads nothing. Materialized: this relation is a table refilled from intent_input_field_resolving_table_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the occurrence path

type_name (CHARACTER VARYING, not null)

the input object type the field is declared on, the occurrence step’s container; with the column beside it, graphql_field’s key for an input coordinate

field_name (CHARACTER VARYING, not null)

the input field’s name within its container

table_source_name (CHARACTER VARYING, not null)

the resolving table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, not null)

the resolving table’s SQL schema

table_name (CHARACTER VARYING, not null)

the resolving table’s SQL name; with the two columns above this is sql_table’s full key, and with the two coordinate columns it is this relation’s grain

intent_input_field_resolving_table_live (view)

This states the rule and is evaluated on demand. The canonical name intent_input_field_resolving_table beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_input_field_resolving_table.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_input_field_resolving_table.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_input_field_resolving_table.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_input_field_resolving_table.field_name, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_input_field_resolving_table.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_input_field_resolving_table.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_input_field_resolving_table.table_name, whose comment carries what the value means

intent_input_occurrence_descent_order (view)

The order the flattener reaches a payload’s occurrences in, one row per occurrence path: a dense zero-based rank within the argument the path descends from. The walk is a depth-first pre-order over declared input fields, so the argument occurrence itself is always rank zero, a grouping input is reached before any field it groups, and a grouping input’s whole subtree lies between it and its next sibling. Two questions already asked that order pairwise, each in its own view body, and both are the same question: which of several contending straddler claims pins a key column, which intent_mutation_write_destination settles, and which occurrence a runtime agreement check names on its predicate side, which intent_mutation_write_agreement settles. A third is the order an emitter renders one statement’s assignments and predicates in, and it is what fixes the grain: all three are questions about an occurrence’s place in one descent, so the order is stated once at the grain of the occurrence rather than three times inside the relations that consume it. The rank is computed pairwise rather than from a sort key assembled out of the path, a key of that shape being a collection folded into one value and this schema keeping no such column: for each pair of occurrences under one argument, the earlier is the one that is a prefix of the other, or, where neither is, the one whose field is declared first at the outermost step the two differ at. That comparison tests field names only and does not compare containers, and does not need to: two paths agreeing on every field name before their first difference agree on every container too, each step’s container being the previous step’s named type and the first being the argument’s own input type, so the containers follow by induction rather than by a predicate. The order is total within an argument, which is what makes the rank dense: two distinct paths under one argument either stand in the prefix relation or take different fields at some step, and different fields on one container have different declaration ordinals. Between arguments it says nothing. Two paths under different arguments both have a rank and the two ranks are not comparable, which is why the argument is not repeated here: a reader needing it joins intent_input_occurrence_path, whose key this relation shares and whose row carries the argument coordinate. Absence is an occurrence path relation with no rows, so a graph declaring no input object surface at all; every path that exists has a rank, the payload root included.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the occurrence path; the leading key dimension that keeps one workspace’s graphs apart

path (CHARACTER VARYING, nullable)

the occurrence this rank is about; with graph_name, the key intent_input_occurrence_path is keyed by, which is what a reader joins on

ordinal (BIGINT, nullable)

zero-based position of the occurrence in its argument’s descent, dense within that argument: the argument occurrence itself is zero, a grouping input precedes every field it groups, and siblings follow their declaration order. Comparable only against another rank under the same argument.

intent_input_occurrence_override (view)

The cascade fact as a predicate over path prefixes: one row per occurrence path with an enclosing @condition(override: true), which in the classification walk is the enclosingOverride boolean threaded through the recursion. A path’s enclosing sites are the use-site field’s own @condition, the argument’s @condition, and the @condition of every step strictly above the leaf (the leaf’s own override is the condition-owned carrier’s fact, not a cascade fact). Absence is the no-override reading, which is what the use-keyed cascade verdict fires on when the leaf is unbound. The witness columns name the nearest enclosing overriding site (deepest step first, then the argument, then the field), the row the admitted-because message and the future fix-it need; a NULL argument name means the witness is a field-site condition row, the witness’s own key shape across the two condition relations.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the path

path (CHARACTER VARYING, nullable)

the overridden occurrence path

override_type_name (CHARACTER VARYING, nullable)

witness: the overriding @condition site’s owning type (an input object type for a step witness)

override_field_name (CHARACTER VARYING, nullable)

witness: the overriding site’s field name

override_argument_name (CHARACTER VARYING, nullable)

witness: the overriding site’s argument name; NULL when the witness is a field-site condition (graphitron_field_condition’s key shape), non-NULL when it is the argument-site relation’s row

intent_input_occurrence_path

One occurrence of the input surface under a use site: an argument whose named type is an input object, or a nested input field reached from one by descending through input-object-typed fields. The key is the serialized path, <root type>.<root field>(<argument>)[/<input field>…​]: an occurrence path is its own identity (no minted coordinate is involved), the relation is re-derived each run so the value key costs nothing, and the step child carries the same data relationally so no consumer parses the key. Every prefix of a path is itself a row. Materialized by a capture-cadence derivation writer for the same reason as intent_type_domain (cyclic input nesting is legal GraphQL and has no safe recursive H2 view form); the expansion stops descending when the leaf type is already visited on the path, which is the classification walk’s own first-visit guard (ClassifyContext.expandingTypes) restated, so the row population equals the recursion tree the build already walks and simple-path enumeration adds no new asymptotic class here.

Primary key: (graph_name, path). Foreign key: (graph_name) references store_graph (graph_name). Foreign key: (graph_name, root_type_name, root_field_name, root_argument_name) references graphql_argument_coordinate (graph_name, type_name, field_name, argument_name).

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

path (CHARACTER VARYING, not null)

the serialized occurrence path; the value key

root_type_name (CHARACTER VARYING, not null)

the use site’s owning type

root_field_name (CHARACTER VARYING, not null)

the use site’s field name within the owning type

root_argument_name (CHARACTER VARYING, not null)

the argument this occurrence descends from

root_input_type (CHARACTER VARYING, not null)

the argument’s named input object type, the traversal’s entry type

leaf_named_type (CHARACTER VARYING, not null)

the named type of the path’s last step (the argument’s own type at depth 0); the expansion descends from here when the type has kind INPUT_OBJECT and is not already visited on the path

depth (INTEGER, not null)

the number of input-field steps below the argument; 0 for the argument occurrence itself, and equal to the highest step ordinal otherwise

intent_input_occurrence_path_step

The ordinal-keyed decomposition of an occurrence path: one row per input-field step, 1-based, so no consumer parses the serialized key. Homogeneous over input-field steps only: the use-site field and argument are fixed by construction (every path has exactly one of each) and live on the parent row, so no column here is nullable by kind. The row at ordinal = depth is the path’s leaf.

Primary key: (graph_name, path, ordinal). Foreign key: (graph_name, path) references intent_input_occurrence_path (graph_name, path). Foreign key: (graph_name, container_type_name, field_name) references graphql_field_coordinate (graph_name, type_name, field_name).

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, anchored through the parent path; the leading key dimension that keeps one workspace’s graphs apart

path (CHARACTER VARYING, not null)

the owning occurrence path

ordinal (INTEGER, not null)

1-based position of this input-field step below the argument

container_type_name (CHARACTER VARYING, not null)

the input object type this step’s field is declared on

field_name (CHARACTER VARYING, not null)

the input field’s name within its container

named_type (CHARACTER VARYING, not null)

the step’s named type; the type the traversal is in after taking this step

intent_mutation_matched_key (view)

Whether a write payload identifies the row it acts on, and through which key. One row per write surface whose payload the walkers admit entirely, which is the population both walkers reach this question at: they collect every per-field refusal first and return before matching a key, on the grounds that an unadmitted field makes the covered set unreliable and a spurious coverage error on top of a real field error helps nobody. So a mutation with any refusal has no row here at all, and that absence is the refusal relation’s to explain rather than a verdict of its own. The match itself is verb-neutral and is the one thing the two walkers genuinely share: which catalog key does this input cover. The candidates and their order are intent_table_key_candidate’s, primary key first and then the unique keys in declaration order with duplicates on the column set already collapsed, so the primary key being the tiebreaker is that relation’s ranking read in ascending order rather than a preference invented here. Covered means every column of the key is one this payload contributes, which is a subset test and not an equality: an input naming more columns than a key needs still covers it, and the surplus is the other consumer’s business. The subset test is counted rather than correlated, the key’s columns outer-joined to the payload’s and the two counts compared, so the contributed columns are read once for the whole matrix instead of once per key column per candidate per surface. That shape also keeps the degenerate reading honest: a candidate with no columns at all compares zero against zero and is covered, which is what a subset test over an empty set does and what the matcher this transcribes would answer. No catalog jOOQ generates produces such a key, so it is a property of the rule rather than a population. What is not verb-neutral is the covered set, and that is the whole reason the verb is on the row. A DELETE counts every admitted column, every one of them being a WHERE predicate. An UPDATE counts only the columns of carriers that pin identity, which is every carrier except a self-referencing foreign key: a self-FK’s columns point at a sibling row, so a key column reachable only through one is not this row’s identity and an UPDATE that treated it as such would key on the wrong row. Stated as a predicate over the carrier role rather than as two relations, because the question and the ranking are identical and only the input to the subset test moves. A closed vocabulary of three. IDENTIFIED names the winning key and carries its rank and whether it is the primary, which is what a consumer emitting the WHERE clause and a diagnostic naming the key both need. BROADCAST is the DELETE that covered nothing and opted in: multiRow: true is the author saying the statement may match many rows, and it is an arm rather than a modifier because the emitted statement has no key predicate at all. UNCOVERED is everything else, and it is a rejection’s population: an UPDATE has no broadcast reading, multiRow: true on one being refused before a write surface exists at all, so an UPDATE whose input pins no key is an author error with the covered columns and the candidate keys as its evidence, both one join from this row. The three key columns are null together and exactly on the two verdicts that name no key, which is the vocabulary determining them rather than an unfilled slot. What this relation does not say is what happens to the columns the key did not take. On a DELETE nothing does, every admitted column being a predicate and the key being a cardinality guard beside them rather than a subset of them. On an UPDATE the key is a partition, and where each remaining column lands, whether a carrier straddles the key, and whether anything is left to set at all are the write destination’s answers over the same substrate this one reduces.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the write payload

type_name (CHARACTER VARYING, nullable)

the type owning the mutation field

field_name (CHARACTER VARYING, nullable)

the mutation field this verdict is about; with the column above and the graph, the grain, one row per write surface

operation (CHARACTER VARYING, nullable)

the verb, UPDATE or DELETE. Not provenance: it selects the covered set the match ran over and it gates the broadcast arm

multi_row (BOOLEAN, nullable)

the @mutation(multiRow:) spelling, carried from the write payload. False on every UPDATE row by construction, that spelling being refused there before a write surface exists

verdict (CHARACTER VARYING, nullable)

IDENTIFIED, BROADCAST or UNCOVERED, a closed vocabulary of three. A fourth outcome is a new value here rather than a silence

write_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table the write targets, and the table whose candidate keys were ranked

write_schema (CHARACTER VARYING, nullable)

the write table’s SQL schema

write_table (CHARACTER VARYING, nullable)

the write table’s SQL name; with the two columns above, sql_table’s full key

constraint_name (CHARACTER VARYING, nullable)

the winning key’s constraint name on that table; NULL on the two verdicts that name no key. With the three table columns above, intent_table_key_candidate’s key, so the key’s own columns are one join away

primary_key (BOOLEAN, nullable)

whether the winning key is the table’s primary key rather than a unique one; NULL where no key won. Carried because a diagnostic and an emitted comment both read differently for the two

candidate_rank (INTEGER, nullable)

the winning key’s 0-based rank among the table’s candidates, carried so a reader can see how far down the order the match had to go without re-ranking; NULL where no key won

source_name (CHARACTER VARYING, nullable)

the @mutation application’s own declaration file; the position a coverage diagnostic would carry

source_line (INTEGER, nullable)

source line of the @mutation application, 1-based

source_column (INTEGER, nullable)

source column of the @mutation application, 1-based

intent_mutation_payload_column

What a write payload actually puts on the table, column by column: one row per admitted occurrence per decode slot, carrying the column that slot binds and what the carrier at the end of it points at. The substrate two relations above it both need and neither should re-derive, the matched key asking which of these columns cover a candidate key and the write destination asking what each one is for. Admitted is the refusal relation’s complement and is read from it rather than restated: no step of this occurrence is a refused site of this mutation. Testing the steps rather than the leaf is what applies the cut, a refused grouping never being descended into, and testing the coordinate rather than the path is exact because a refusal under one mutation is a property of the input field and the write table and both are fixed for the whole payload. The population is then the two column-resolving roles and nothing else, a nesting having no column of its own and the other three roles being refusals here. Two arms, one per role, and they differ in arity rather than in kind. A name match is one column at position zero, which is the plain field and the empty reference path alike. A node id is one row per position of the decoded key, so a compound key is a compound contribution and the emitter reads its value at the slot this column names. That is why position is a column and not an implicit ordering: the UPDATE partition splits a cross-table foreign key per column, and once split, neither half’s ordering recovers which slot of the decode a column came from. The decode is joined on the occurrence path alone with no guard on where it departs, which is safe here and would not be at a read site. A decode’s departure is the consuming argument’s scope, and that is one table per branch where the consuming field returns a multi-table polymorphic container. A write payload has no such branch: the participant arm’s own precondition is that the field’s named type binds no table and that the field carries no resolving @mutation(table:) spelling, and each of the three write rungs contradicts one of those. So the argument here has exactly one scope table, it is the write table, and there is no second branch for the join to pick up. The carrier role travels on the row because both consumers fork on it and neither should join back for it. The UPDATE walker counts only non-self-FK columns toward the key match, a self-FK’s columns pointing at a sibling row and never at this row’s identity, and it routes a self-FK’s columns wholly to the SET half however they fall against the key. Neither fact is derivable from the column. Absence is a payload with no column-bearing occurrence in it, and every occurrence the walkers refuse, which the refusal relation states with a cause. This relation says nothing about what a column is for. A column reached from a DELETE is a predicate and one reached from an UPDATE is a predicate or an assignment depending on the matched key it is measured against, and the key is not known until every row here is. Materialized: this relation is a table refilled from intent_mutation_payload_column_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the write payload

type_name (CHARACTER VARYING, not null)

the type owning the mutation field, which is the occurrence path’s root type

field_name (CHARACTER VARYING, not null)

the mutation field whose payload contributes this column

operation (CHARACTER VARYING, not null)

the verb the walker was flattening for, UPDATE or DELETE; carried because the covered set the matched key computes over differs between them

path (CHARACTER VARYING, not null)

the occurrence path of the contributing input field; with the graph and the position, this relation’s grain

container_type_name (CHARACTER VARYING, not null)

the input object type the contributing field is declared on

input_field_name (CHARACTER VARYING, not null)

the contributing input field’s name within that container; named apart from field_name because that column is the mutation’s

role (CHARACTER VARYING, not null)

which rule resolved the column, NAME_MATCHED or NODE_ID, carried from the filter role. The two arms of this relation, and what tells a one-column contribution from a decoded tuple without counting rows

carrier_role (CHARACTER VARYING, not null)

what the carrier points at, OWN_COLUMNS, SELF_FK or CROSS_TABLE_FK, carried from the carrier role relation. REMOTE cannot appear, a remote carrier being a refusal at this site rather than a contribution

position (INTEGER, not null)

the 0-based decode slot within the contributing field’s own column tuple: always zero for a name match, and the node key’s position for a decode. What the emitter reads the value at, and the one fact a split carrier’s two halves cannot recover between them

column_name (CHARACTER VARYING, not null)

the column on the write table this slot binds, as the catalog spells it. Never null: a decode with a position that lands nowhere is a remote carrier and is refused before it reaches here

write_source_name (CHARACTER VARYING, not null)

the catalog partition of the table the write targets, which is also the table the field was classified against

write_schema (CHARACTER VARYING, not null)

the write table’s SQL schema

write_table (CHARACTER VARYING, not null)

the write table’s SQL name; with the two columns above, sql_table’s full key, and with the column name above, sql_column’s

source_name (CHARACTER VARYING, not null)

the contributing input field’s own declaration file; the position a diagnostic naming this column would carry

source_line (INTEGER, nullable)

source line of the input field declaration, 1-based

source_column (INTEGER, nullable)

source column of the input field declaration, 1-based

intent_mutation_payload_column_live (view)

This states the rule and is evaluated on demand. The canonical name intent_mutation_payload_column beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_mutation_payload_column.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_mutation_payload_column.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_mutation_payload_column.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_mutation_payload_column.field_name, whose comment carries what the value means

operation (CHARACTER VARYING, nullable)

the operation of a row of this rule, materialized into intent_mutation_payload_column.operation, whose comment carries what the value means

path (CHARACTER VARYING, nullable)

the path of a row of this rule, materialized into intent_mutation_payload_column.path, whose comment carries what the value means

container_type_name (CHARACTER VARYING, nullable)

the container_type_name of a row of this rule, materialized into intent_mutation_payload_column.container_type_name, whose comment carries what the value means

input_field_name (CHARACTER VARYING, nullable)

the input_field_name of a row of this rule, materialized into intent_mutation_payload_column.input_field_name, whose comment carries what the value means

role (CHARACTER VARYING, nullable)

the role of a row of this rule, materialized into intent_mutation_payload_column.role, whose comment carries what the value means

carrier_role (CHARACTER VARYING, nullable)

the carrier_role of a row of this rule, materialized into intent_mutation_payload_column.carrier_role, whose comment carries what the value means

position (INTEGER, nullable)

the position of a row of this rule, materialized into intent_mutation_payload_column.position, whose comment carries what the value means

column_name (CHARACTER VARYING, nullable)

the column_name of a row of this rule, materialized into intent_mutation_payload_column.column_name, whose comment carries what the value means

write_source_name (CHARACTER VARYING, nullable)

the write_source_name of a row of this rule, materialized into intent_mutation_payload_column.write_source_name, whose comment carries what the value means

write_schema (CHARACTER VARYING, nullable)

the write_schema of a row of this rule, materialized into intent_mutation_payload_column.write_schema, whose comment carries what the value means

write_table (CHARACTER VARYING, nullable)

the write_table of a row of this rule, materialized into intent_mutation_payload_column.write_table, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_mutation_payload_column.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_mutation_payload_column.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_mutation_payload_column.source_column, whose comment carries what the value means

intent_mutation_payload_key_membership

Which of the columns an UPDATE’s payload contributes fall inside the key it matched, and how each carrier as a whole falls against that boundary. The substrate the write destination and the write refusal both reduce, and a relation of its own rather than a step inside either because both of them need the per-column answer and the per-carrier one together: where a column goes turns on where its carrier falls and not only on where the column does. It is also what the straddle diagnostic renders, that error carrying exactly the two column lists this relation partitions one carrier into. The population is the write payload’s narrowed in two directions at once, and both narrowings are the walkers'. The verb is UPDATE alone. A DELETE matches a key too, but that key is a cardinality guard rather than a partition and every admitted column of a DELETE is a predicate whatever it does against it, so measuring a DELETE here would answer a question no consumer of one asks and invite a partition to be read into a statement that has none. And the verdict is IDENTIFIED alone: a payload that pins no key has no boundary to be measured against, and the broadcast arm is a DELETE’s and leaves with the verb. The column answer and the carrier answer are two columns and not one. in_key is the column’s own, a lookup against the named constraint’s columns, and the constraint travels on the row because the boundary is the key the ranking picked rather than the primary key and a consumer rendering a diagnostic has to say which. carrier_key_membership is the same question asked of every column of the occurrence at once, in a closed vocabulary of three. WHOLE is a carrier every column of which is in the key and NONE one no column of which is; the answer is an all-of rather than a majority, which is what makes the remaining value a straddle rather than a lean. STRADDLE is a carrier with a column on each side, and it is the only shape whose columns may be dispositioned apart. The carrier-level value is repeated down the carrier’s columns rather than being a relation of its own, because both consumers fork on the pair: a row carrying only the column answer would send each of them back for the carrier’s, and a relation at the carrier grain would make the column answer a second join. What this relation does not say is what any of it means. A straddling carrier of the row’s own columns is refused, a straddling reference is split or refused depending on how it is spelled, and a self-referencing foreign key is exempt from the whole question; none of that is a fact about membership, and all of it is the destination’s and the refusal’s one join from here. Absence is every write payload the two narrowings exclude, and every payload with no column-bearing occurrence in it. Materialized: this relation is a table refilled from intent_mutation_payload_key_membership_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the payload column

type_name (CHARACTER VARYING, not null)

the type declaring the mutation field, which is the occurrence path’s root type

field_name (CHARACTER VARYING, not null)

the mutation field; with the type, the coordinate whose key this membership is measured against

path (CHARACTER VARYING, not null)

the occurrence path of the contributing input field, intent_input_occurrence_path’s key; with the position and the graph, this relation’s grain

container_type_name (CHARACTER VARYING, not null)

the input object type the contributing field is declared on, the path’s last step’s container

input_field_name (CHARACTER VARYING, not null)

the contributing field’s name within that container; named apart from field_name because that column is the mutation’s

role (CHARACTER VARYING, not null)

which rule resolved the column, NAME_MATCHED or NODE_ID, carried from the payload column so a consumer forking on whether the value is decoded does not join back for it

carrier_role (CHARACTER VARYING, not null)

what the carrier points at, carried for the same reason. Both consumers fork on it: a self-referencing foreign key is exempt from the partition altogether and a cross-table one is the only carrier that may be split

position (INTEGER, not null)

the decode slot this column binds, counting from zero, and zero for a name match. Carried because the split is per column and neither half of a split carrier recovers the slot from its own ordering

column_name (CHARACTER VARYING, not null)

the column of the write table this slot binds

in_key (BOOLEAN, not null)

whether this column is one of the matched key’s, which is a lookup against sql_constraint_column for the constraint named beside it

carrier_key_membership (CHARACTER VARYING, not null)

how the whole carrier falls against that boundary: WHOLE where every column of it is in the key, NONE where none is, STRADDLE where it has a column on each side. A closed vocabulary of three, and an all-of over the carrier’s columns rather than a majority

constraint_name (CHARACTER VARYING, not null)

the key the membership is measured against, which is the candidate intent_mutation_matched_key ranked first among those this payload covers. On the row because the boundary is that key rather than the primary key, and a diagnostic has to name it

write_source_name (CHARACTER VARYING, not null)

the catalog partition of the table the write targets

write_schema (CHARACTER VARYING, not null)

the write table’s SQL schema

write_table (CHARACTER VARYING, not null)

the write table’s SQL name; with the two columns above, sql_table’s full key

source_name (CHARACTER VARYING, not null)

the contributing input field’s own declaration file; the position a refusal about this carrier would carry

source_line (INTEGER, nullable)

source line of the input field declaration, 1-based

source_column (INTEGER, nullable)

source column of the input field declaration, 1-based

intent_mutation_payload_key_membership_live (view)

This states the rule and is evaluated on demand. The canonical name intent_mutation_payload_key_membership beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_mutation_payload_key_membership.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_mutation_payload_key_membership.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_mutation_payload_key_membership.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_mutation_payload_key_membership.field_name, whose comment carries what the value means

path (CHARACTER VARYING, nullable)

the path of a row of this rule, materialized into intent_mutation_payload_key_membership.path, whose comment carries what the value means

container_type_name (CHARACTER VARYING, nullable)

the container_type_name of a row of this rule, materialized into intent_mutation_payload_key_membership.container_type_name, whose comment carries what the value means

input_field_name (CHARACTER VARYING, nullable)

the input_field_name of a row of this rule, materialized into intent_mutation_payload_key_membership.input_field_name, whose comment carries what the value means

role (CHARACTER VARYING, nullable)

the role of a row of this rule, materialized into intent_mutation_payload_key_membership.role, whose comment carries what the value means

carrier_role (CHARACTER VARYING, nullable)

the carrier_role of a row of this rule, materialized into intent_mutation_payload_key_membership.carrier_role, whose comment carries what the value means

position (INTEGER, nullable)

the position of a row of this rule, materialized into intent_mutation_payload_key_membership.position, whose comment carries what the value means

column_name (CHARACTER VARYING, nullable)

the column_name of a row of this rule, materialized into intent_mutation_payload_key_membership.column_name, whose comment carries what the value means

in_key (BOOLEAN, nullable)

the in_key of a row of this rule, materialized into intent_mutation_payload_key_membership.in_key, whose comment carries what the value means

carrier_key_membership (CHARACTER VARYING, nullable)

the carrier_key_membership of a row of this rule, materialized into intent_mutation_payload_key_membership.carrier_key_membership, whose comment carries what the value means

constraint_name (CHARACTER VARYING, nullable)

the constraint_name of a row of this rule, materialized into intent_mutation_payload_key_membership.constraint_name, whose comment carries what the value means

write_source_name (CHARACTER VARYING, nullable)

the write_source_name of a row of this rule, materialized into intent_mutation_payload_key_membership.write_source_name, whose comment carries what the value means

write_schema (CHARACTER VARYING, nullable)

the write_schema of a row of this rule, materialized into intent_mutation_payload_key_membership.write_schema, whose comment carries what the value means

write_table (CHARACTER VARYING, nullable)

the write_table of a row of this rule, materialized into intent_mutation_payload_key_membership.write_table, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_mutation_payload_key_membership.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_mutation_payload_key_membership.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_mutation_payload_key_membership.source_column, whose comment carries what the value means

intent_mutation_payload_refusal

Why a walker-driven write refuses one input field, located at the occurrence that reaches it. The refusal half of intent_mutation_write_payload: that relation folds the three refusals an argument owns into its own absence and deliberately leaves these out of it, because each of them is a refusal at a coordinate an author can be pointed at, and folding them into one silence at the mutation would throw the position away. The grain is the occurrence path rather than the input field, so a shared input type reached from two write surfaces is refused once under each and every row names both the mutation it broke and the step inside the payload that broke it. The path carries the mutation coordinate as its root, so the coordinate columns beside it are a projection rather than a widening of the key. The domain is the write payload’s and therefore the two verbs whose input a walker flattens, UPDATE and DELETE. An INSERT admits its payload through a gate of its own, which rejects a @lookupKey and a composing @condition on the input type outright and admits the condition-owned field this relation refuses, so its refusals are not these and putting them here would make one vocabulary stand for two rules. Two gates, in the order the build runs them, and the vocabulary keeps them apart. UNCLASSIFIED is the first and is not a walker’s refusal at all: the classifier declined the field, the validator mirror lifts that decline into a rejection on the mutation, and the walker never runs. Why it declined is intent_input_field_filter_role’s absence and the resolution relations under it; the cause here says which gate refused and leaves the diagnostic where the rule is stated. The other five are the walkers' own, and they are one set rather than two: the DELETE and UPDATE flatteners refuse the same five shapes at the same two gates, and the only thing that differs between them is which typed error carries the message. The five are ranked rather than unioned because a field can be several of them at once and the build reports the first. REMOTE_CARRIER is decided at the binding switch ahead of every other test, so a reference carrier whose decoded value reaches its row only through a join is refused for that and not for whatever else it also is. CONDITION_OWNED and UNBOUND are carriers of their own and never reach the shape gate below them. LIST_CARRIER is that gate’s first test and AUTHORED_CONDITION its second, which is the order a list-typed field carrying a @condition is reported in. The role sits beside the cause because two of the causes cover two sites each. A list-typed field is refused whether it is a leaf carrier or a nesting grouping, and so is a field carrying a @condition; the walkers report those as four messages and this relation as two causes, the role telling a reader which of the four a row is. Widening the vocabulary instead would have restated at this grain a distinction the role relation already draws. AUTHORED_CONDITION is any @condition on a field whose role is not CONDITION_OWNED, of either override value, because what the walkers refuse is the directive on a shape they would otherwise admit rather than one of its readings: an override: true condition beside a @nodeId or a @reference is refused exactly as a composing one is, the classifier having given that field its own arm rather than the condition-owned carrier. That is also why this cause is not read off the role relation’s authored_condition column, which by construction says nothing about the override: true case. A refused nesting is never descended into, so nothing below it is classified and nothing below it is refused. This relation states that as a cut rather than as a rule: no row is emitted at a path any strict prefix of which carries a refusal of its own, whichever cause that prefix carries. The circular-nesting cut is not restated here at all, being intent_input_occurrence_path’s and already applied to the population this relation drives from. Absence is a payload the walkers admit at every occurrence of its input surface, which is the ordinary working write surface, and it is not a claim that the write succeeds. Whether the admitted remainder identifies a row is the matched key’s question and a refusal of the mutation rather than of a field, so it has no coordinate to be located at and no row here. Materialized: this relation is a table refilled from intent_mutation_payload_refusal_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the write payload

type_name (CHARACTER VARYING, not null)

the type owning the refused mutation field, which is the occurrence path’s root type

field_name (CHARACTER VARYING, not null)

the mutation field whose payload this row refuses; with the column above, the coordinate intent_mutation_write_payload is keyed by

operation (CHARACTER VARYING, not null)

the verb the walker was flattening for, UPDATE or DELETE. Carried because the two mint different typed errors from the same five refusals, so a consumer rendering one needs the verb without a second join

path (CHARACTER VARYING, not null)

the occurrence path of the refused input field, intent_input_occurrence_path’s key; with the graph, this relation’s grain

container_type_name (CHARACTER VARYING, not null)

the input object type the refused field is declared on, the path’s last step’s container

input_field_name (CHARACTER VARYING, not null)

the refused input field’s name within that container; named apart from field_name because that column is the mutation’s

role (CHARACTER VARYING, nullable)

the role the classifier resolved for the field, which says which of the sites a cause covering two of them is about. NULL exactly where the cause is UNCLASSIFIED, the classifier having resolved no role to carry

cause (CHARACTER VARYING, not null)

which gate refused and why, in a closed vocabulary of six: UNCLASSIFIED where the classifier declined the field before a walker saw it, then the walkers' own five in the order they are tested, REMOTE_CARRIER, CONDITION_OWNED, UNBOUND, LIST_CARRIER and AUTHORED_CONDITION. A new refusal in either walker is a new value here rather than a silence

write_source_name (CHARACTER VARYING, not null)

the catalog partition of the table the write targets, which is also the table the field was classified against; carried so a reader has the classification this refusal was reached under

write_schema (CHARACTER VARYING, not null)

the write table’s SQL schema

write_table (CHARACTER VARYING, not null)

the write table’s SQL name; with the two columns above, sql_table’s full key

source_name (CHARACTER VARYING, not null)

the refused input field’s own declaration file; the position a diagnostic would carry, and the whole reason these refusals are stated here rather than folded into the payload relation’s absence

source_line (INTEGER, nullable)

source line of the input field declaration, 1-based

source_column (INTEGER, nullable)

source column of the input field declaration, 1-based

intent_mutation_payload_refusal_live (view)

This states the rule and is evaluated on demand. The canonical name intent_mutation_payload_refusal beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_mutation_payload_refusal.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_mutation_payload_refusal.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_mutation_payload_refusal.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_mutation_payload_refusal.field_name, whose comment carries what the value means

operation (CHARACTER VARYING, nullable)

the operation of a row of this rule, materialized into intent_mutation_payload_refusal.operation, whose comment carries what the value means

path (CHARACTER VARYING, nullable)

the path of a row of this rule, materialized into intent_mutation_payload_refusal.path, whose comment carries what the value means

container_type_name (CHARACTER VARYING, nullable)

the container_type_name of a row of this rule, materialized into intent_mutation_payload_refusal.container_type_name, whose comment carries what the value means

input_field_name (CHARACTER VARYING, nullable)

the input_field_name of a row of this rule, materialized into intent_mutation_payload_refusal.input_field_name, whose comment carries what the value means

role (CHARACTER VARYING, nullable)

the role of a row of this rule, materialized into intent_mutation_payload_refusal.role, whose comment carries what the value means

cause (CHARACTER VARYING, nullable)

the cause of a row of this rule, materialized into intent_mutation_payload_refusal.cause, whose comment carries what the value means

write_source_name (CHARACTER VARYING, nullable)

the write_source_name of a row of this rule, materialized into intent_mutation_payload_refusal.write_source_name, whose comment carries what the value means

write_schema (CHARACTER VARYING, nullable)

the write_schema of a row of this rule, materialized into intent_mutation_payload_refusal.write_schema, whose comment carries what the value means

write_table (CHARACTER VARYING, nullable)

the write_table of a row of this rule, materialized into intent_mutation_payload_refusal.write_table, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_mutation_payload_refusal.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_mutation_payload_refusal.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_mutation_payload_refusal.source_column, whose comment carries what the value means

intent_mutation_routine_seat (view)

Which seat a mutation root’s @routine occupies, and where it occupies none, which precondition stopped it. A @routine on a mutation root is a write, and there are exactly two shapes the write can take: the chain seat, where @reference elements after the routine say where the committed row is re-read from, and the carrier seat, where the field returns a payload whose one data field re-reads it by the routine result’s name-matched keys. Which of the two the author wrote for is the seat, and whether that seat holds is the verdict, and they are separate columns because a refused coordinate still has a seat and a diagnostic about it has to name the shape the author was aiming at. Population: every mutation-root field carrying @routine, at the application that defines the chain. Total over that population and exactly one row per coordinate, which is the property the whole relation is for: there is no default arm and no coordinate with no row, so a shape this vocabulary cannot name is a build failure here rather than a silent non-member somewhere downstream. A reduction over sibling relations rather than a rule of its own: every fact it turns on is already a relation, intent_field_chain_terminus and intent_field_chain_node for where the chain goes, intent_carrier_data_field and intent_carrier_routine_hop for what the payload is and where its re-read departs from, intent_bound_table for what the author wrote @table for, and the captured directive rows for what was written. What this relation adds is the seat fork and the precedence, and nothing else; a verdict that needed a fact no relation states would be a rule wearing a reduction’s name, and the two the walk distinguishes that no relation states are disclosed below rather than fabricated here. One pass with the verdict picked by a CASE rather than one UNION ALL arm per verdict, which is intent_node_id_decode_defect’s rule for the same reason and additionally for this one: exactly-one-verdict-per-coordinate is what a reader trusts, and one driving row gives it by construction where a union would have to rank arms to get it back. The nesting is the seat fork, so the two seats' arms cannot reach each other. Precedence is this relation’s own and not a transcription of any evaluation order: a coordinate with two defects gets the more fundamental one, the count of routine nodes before the chain’s head, the head before the surface written on it, the surface before anything about the return, and the return’s shape before where the chain lands. There is no message column, on intent_node_id_decode_defect’s settled terms: the closed vocabulary plus the coordinate and the return type are the fact base, and the prose that renders a verdict as a sentence an author can act on belongs with the consumer that composes it. Nor a severity column, which would be a function of the verdict and nothing else; which verdicts are the author’s to fix and which are shapes the generator owes an emitter is stated per value below. The terminus rule reads intent_bound_table and not intent_resolved_type_binding, and the choice is load-bearing rather than inherited: the reduction’s other arm is intent_routine_return_binding, which binds a chain field’s return type to that same chain’s terminus, so comparing the terminus against the reduction would be comparing a value with itself. What the rule is actually about is whether the table the author wrote @table for is where the chain lands, which is the @table population’s question alone; this is intent_inferred_node_type’s reason for standing on that arm too. A return type carrying no @table therefore draws no disagreement, the derived binding governing there, which is the shipped behaviour and not an omission. Two silences are disclosed rather than closed. A first hop that joins by an authored condition alone resolves to no hop row at all, so it reads here as CHAIN_UNRESOLVED where the classification walk calls it a shape owed an emitter; separating them needs the stalled step named, and the tail a chain walks is intent_field_chain_node’s own and not a relation. And a payload whose data field is the ID scalar draws no intent_carrier_data_field row at all, that relation refusing an ID element for the ROUTINE family outright, so it reads as NO_CARRIER and CARRIER_ELEMENT_NOT_TABLE names the record element alone.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the @routine application

type_name (CHARACTER VARYING, nullable)

the mutation root type the field sits on, bound by graphql_root_operation at MUTATION rather than by the literal name Mutation, on the demand rules' terms

field_name (CHARACTER VARYING, nullable)

the mutation field the @routine is written on; with the type above, the coordinate the write runs at and a located refusal attaches to

ordinal (INTEGER, nullable)

the chain-defining @routine application’s own ordinal, which is the greatest on the field; joins back to graphitron_routine on it. The selection is intent_field_chain_start’s rule reached without its resolution, spelled again here for a reason that relation cannot serve: this population must hold a row where a routine name resolves to nothing, and there it has none

seat (CHARACTER VARYING, nullable)

which shape the field’s applications were written for, a closed two-value domain. CHAIN: the field carries at least one @reference, so the routine call is the write and the chain’s terminus is where the post-commit re-read runs. CARRIER: it carries none, so the return is a payload type whose data field owns the re-read and the hop out of the routine result is inferred rather than written. Decided by the presence of an @reference application and by nothing else, which is why it is a fact about the coordinate rather than a verdict: a refused coordinate has a seat too, and the two seats' verdicts are disjoint vocabularies below the three shared ones

verdict (CHARACTER VARYING, nullable)

whether the seat holds, and where it does not, which precondition stopped it, in a closed vocabulary of fourteen. ADMITTED is the one emitting value and means the seat’s whole predicate holds; what such a coordinate emits is the seat column’s to say. Three refusals are shared by both seats. MULTIPLE_ROUTINE_NODES: more than one @routine is written on the field, which is a shape owed the multi-lateral emit; it precedes every other verdict because the rules below are stated about the chain’s one routine and there is no one routine here. CHAIN_HEAD_NOT_ROUTINE: an @reference is written before the routine, so the chain would depart from something other than the function result, which at a root there is nothing to be. READ_SURFACE_ON_WRITE: the field or one of its arguments carries @condition or @orderBy, and neither write seat has a filter or an ordering to resolve them against, so admitting the coordinate would classify the directives clean and then silently do nothing. Five are the chain seat’s. REFERENCE_ON_CARRIER_RETURN: the return carries no @table and is a routine payload carrier, so the path is the right fact at the wrong grain and its seat is the payload’s data field. CONNECTION_RETURN: @asConnection rewrote the field’s type expression, and the write’s re-read is keyed by the captured routine columns rather than paginated. CHAIN_UNRESOLVED: the chain does not land on exactly one table, which covers a routine name resolving to no function result, a walk that stopped short of the written tail, and a step reaching its destination by more than one route; which of the three it is is readable on intent_field_chain_node at this row’s own coordinate. UNANCHORED_FIRST_HOP: the first hop out of the routine result carries an authored condition, whose predicate names the routine alias and so cannot appear in the follow-up query, leaving the re-read no anchor. TERMINUS_NOT_RETURN_TABLE: the return type’s @table names a table the chain does not land on, or names one ambiguously. Five are the carrier seat’s. TABLE_BOUND_RETURN: the return is @table-bound with no @reference to walk, which is the chain shape minus its chain and has no re-read anchor either. NO_CARRIER: the return is neither table-bound nor a payload declaring exactly one data channel of the routine family, which is intent_carrier_data_field’s arity and its whole set of refusals reported as one. CARRIER_ELEMENT_NOT_TABLE: the one data channel is a record element, and a routine write re-reads its committed row from a catalog table. CARRIER_DATA_FIELD_NON_NULL: the data channel is a non-null single, so a re-read a read policy legitimately returns no row for would null the whole payload through non-null propagation and destroy the errors list beside it. CARRIER_HOP_UNRESOLVED: no hop runs from this field’s own routine result to the data field’s table, or one does and the pairing it would key on comes up short of the arrival’s key, which is intent_name_matched_key_pair’s shortfall stated as rows and demanded here as the reader’s own gate, intent_carrier_routine_hop naming the two ends and never claiming they can be keyed. Of the fourteen, the ones an author fixes in their own schema are CHAIN_HEAD_NOT_ROUTINE, REFERENCE_ON_CARRIER_RETURN, TERMINUS_NOT_RETURN_TABLE, CARRIER_ELEMENT_NOT_TABLE, CARRIER_DATA_FIELD_NON_NULL and CARRIER_HOP_UNRESOLVED; MULTIPLE_ROUTINE_NODES, READ_SURFACE_ON_WRITE, CONNECTION_RETURN, UNANCHORED_FIRST_HOP and TABLE_BOUND_RETURN are shapes the generator owes an emitter; CHAIN_UNRESOLVED and NO_CARRIER are each of both kinds and the witness relation tells them apart

return_type_name (CHARACTER VARYING, nullable)

the type the field returns, read off intent_field_navigated_type, so a connection-returning field names its element whether the generator synthesised that connection or the author declared it. On a CHAIN row this is the type the chain’s terminus stands for; on a CARRIER row it is the payload, and the key into intent_carrier_data_field for the data channel this seat’s re-read runs at. Never the table: what table stands for the type is intent_bound_table’s and intent_field_chain_terminus’s to say, and repeating it here would be a denormalisation of facts this row’s own columns already reach

source_name (CHARACTER VARYING, nullable)

the schema document the @routine application is written in, carried from graphitron_routine so a located refusal needs no join back to the population

source_line (INTEGER, nullable)

source line, 1-based per the graphql-java convention

source_column (INTEGER, nullable)

source column, 1-based per the graphql-java convention. With the line and the document name, the site a refusal points an author at, which is the directive and not the field, every verdict here being about what the @routine composes with

intent_mutation_write_agreement (view)

Which two of an UPDATE’s contributions must be checked equal before any DML runs, one row per pair per column. A foreign key forces the two values equal for well-formed input and nothing forces the input to be well formed: both values arrive on the wire independently, so a disagreement is a runtime error and can only be a runtime error, which is why this states an obligation to emit a check rather than a refusal to generate. It is a reduction over intent_mutation_write_destination rather than a fact beside it, and the whole of the rule is a self-join and a tie-break: every pair is a PREDICATE row of that relation and a non-PREDICATE row of it over the same column of the same statement. Two carriers reach the non-PREDICATE side and the destination already tells them apart. A self-referencing foreign key routes every column it carries to the assignment half, so a key column among them is written and checked, and its row here carries VALUE. A straddling cross-table reference whose in-key column something else already pins neither filters nor writes it, so its row here carries CHECKED, which is that destination’s whole reason to exist. The predicate side is one occurrence per column even where several are dispositioned PREDICATE, because the statement filters on a column once: where two whole carriers bind one key column, which of them the check names is the flattener’s descent order, read off intent_input_occurrence_descent_order, which is the same rank intent_mutation_write_destination settles a contested straddler claim with, and asked here rather than left to whatever order a row arrives in for the same reason it is asked there. A field paired with itself is excluded in the join rather than filtered after it: the check this lowers to names two input fields, and a field cannot disagree with itself, so an occurrence and a same-named occurrence elsewhere in the payload produce no obligation. Absence is every payload with no reference carrier landing on a key column, which is most of them, and every payload the write partition refuses, a refused payload having no destination rows to reduce over. Source positions are not carried: a row here names two occurrences, both of which intent_mutation_write_destination already carries a position for at a key this relation states in full, and carrying one of the two would invite it to be read as the obligation’s position, which no author error attaches to. Nor is the order the checks are emitted in carried as a column. That order is the reference occurrence’s place in the flattener’s descent and then its decode slot, which is the order the assignment and predicate halves are themselves emitted in, so it is one question at the grain of an occurrence rather than three at the grain of each partition; the descent half of it is intent_input_occurrence_descent_order, which an emitter joins on the reference path, and the decode slot is reference_position here.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the write destination

type_name (CHARACTER VARYING, nullable)

the type declaring the mutation field whose statement the check runs before

field_name (CHARACTER VARYING, nullable)

the mutation field; with the type, the coordinate both sides belong to and the statement the check guards

column_name (CHARACTER VARYING, nullable)

the column of the write table both sides supply a value for, and the column whose SQL type the comparison is coerced through

key_path (CHARACTER VARYING, nullable)

the occurrence path of the contributing input field the WHERE clause reads, intent_input_occurrence_path’s key

key_container_type_name (CHARACTER VARYING, nullable)

the input object type the predicate side’s field is declared on, its path’s last step’s container

key_input_field_name (CHARACTER VARYING, nullable)

the predicate side’s field name within that container, the first of the two names a disagreement quotes

key_position (INTEGER, nullable)

the decode slot of the predicate side’s carrier holding this column’s value, counting from zero, and zero for a name match

key_role (CHARACTER VARYING, nullable)

which rule resolved the predicate side’s column, NAME_MATCHED or NODE_ID. It is the one thing about the two sides that varies, the reference side always being a decode, so a consumer deciding which side it can read a decoder off reads this and joins back for nothing

reference_path (CHARACTER VARYING, nullable)

the occurrence path of the reference carrier that supplies the column’s other value

reference_container_type_name (CHARACTER VARYING, nullable)

the input object type the reference side’s field is declared on

reference_input_field_name (CHARACTER VARYING, nullable)

the reference side’s field name within that container, the second name a disagreement quotes; never equal to key_input_field_name

reference_position (INTEGER, nullable)

the decode slot of the reference carrier holding this column’s value. Carried rather than derived because a straddling carrier’s columns are split across the two halves of the statement, after which neither half’s ordering recovers which slot a column came from

reference_destination (CHARACTER VARYING, nullable)

what the reference side’s column is for in the statement, VALUE or CHECKED, carried from intent_mutation_write_destination. VALUE is the self-referencing foreign key, which writes the column as well as being checked on it; CHECKED is the straddler that does neither. A consumer emitting the assignment half reads this to know whether the column is already covered there

write_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table the write targets

write_schema (CHARACTER VARYING, nullable)

the write table’s SQL schema

write_table (CHARACTER VARYING, nullable)

the write table’s SQL name; with the two columns above, sql_table’s full key

intent_mutation_write_destination

What each column a write payload contributes is for, one row per contributing occurrence per decode slot: the finished partition, and what an emitter assembles a statement out of. The verb decides how many destinations are reachable at all. A DELETE reaches one. Every admitted column of it is a predicate and the matched key is a cardinality guard beside them rather than a subset of them, so the broadcast arm contributes predicates exactly as the identified one does and a self-referencing foreign key filters there exactly as a plain column does. An UPDATE reaches all three, and which one a column reaches turns on its carrier rather than on the column. A carrier wholly inside the key filters. One wholly outside it writes. A self-referencing foreign key writes however it falls, its columns pointing at a sibling row rather than at this one, so a key column it carries is an ordinary assignment and the foreign key forces it equal to what the predicate matched. A cross-table foreign key is the one carrier that splits, its in-key half being this row’s own identity and its out-of-key half a value, which is why the decode slot is a column here and not an implicit ordering: once a carrier is split, neither half recovers which slot of the decode a column came from. CHECKED is the destination that is easy to miss and the reason the vocabulary is not two values. Where a straddler’s in-key column is already pinned by some other carrier, the straddler neither filters nor writes it: the two decoded values are compared before any DML runs and the column has a contribution and no place in the statement. It is stated rather than left as an absence, an absence at this grain saying that the occurrence contributes nothing to that column, which is not what happens. Which carrier pins a contested key column, where more than one straddler claims it and nothing else does, is the walker’s input-field order, the first claim supplying the predicate and the rest being checked. The choice is observationally irrelevant, the agreement check running either way, but it decides which field’s decode appears in the emitted WHERE clause, so it is transcribed rather than left to whatever order a row arrives in. The order is the flattener’s descent, which intent_input_occurrence_descent_order ranks every occurrence of a payload by; this relation reads that rank and keeps the earliest claim, rather than comparing the contenders itself. It compared them itself first, and stopped when the second reader wanting the same order arrived: a comparison spelled twice is a rule stated twice, and the grain it is really asked at is the occurrence rather than the contested column. A refused payload contributes nothing at all: the walker returns before building either half, so a coordinate with any refusal has no row here whichever of the three refusal relations carries it. The exclusion against the partition-stage refusals is written as a set difference rather than as a test per row, the per-row form re-deriving that whole rule once for every column it filters. Absence is a refused payload, a payload with no column-bearing occurrence in it, and every mutation offering no write surface at all. Which pairs of contributions must agree at runtime is the one thing this relation does not decide and intent_mutation_write_agreement does, as a reduction over these rows rather than a fact beside them: every such pair is a predicate row and a non-predicate row here over one column of one statement. Materialized: this relation is a table refilled from intent_mutation_write_destination_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the write payload

type_name (CHARACTER VARYING, not null)

the type declaring the writing mutation field

field_name (CHARACTER VARYING, not null)

the mutation field whose statement this column takes part in; with the type, the coordinate intent_mutation_write_payload is keyed by

operation (CHARACTER VARYING, not null)

the verb as the author wrote it, UPDATE or DELETE. On the row because the destination is not derivable without it: the same payload over the same table disposes its columns differently under the two verbs

path (CHARACTER VARYING, not null)

the occurrence path of the contributing input field, intent_input_occurrence_path’s key; with the position and the graph, this relation’s grain

container_type_name (CHARACTER VARYING, not null)

the input object type the contributing field is declared on, the path’s last step’s container

input_field_name (CHARACTER VARYING, not null)

the contributing field’s name within that container; named apart from field_name because that column is the mutation’s

role (CHARACTER VARYING, not null)

which rule resolved the column, NAME_MATCHED or NODE_ID; carried so a consumer emitting the extraction knows whether the value is decoded without joining back for it

carrier_role (CHARACTER VARYING, not null)

what the carrier points at, which is what the disposition turned on and what a diagnostic explaining the disposition names

position (INTEGER, not null)

the decode slot this column binds, counting from zero, and zero for a name match. The one place the slot survives: a split carrier’s two halves each lose the other’s ordering, so a consumer reading one of them cannot recover it

column_name (CHARACTER VARYING, not null)

the column of the write table this row’s value reaches

destination (CHARACTER VARYING, not null)

what the column is for, in a closed vocabulary of three. PREDICATE where the statement finds its row by this column, VALUE where it assigns it, CHECKED where it does neither and the contribution is only compared against the predicate’s value before the statement runs

write_source_name (CHARACTER VARYING, not null)

the catalog partition of the table the write targets

write_schema (CHARACTER VARYING, not null)

the write table’s SQL schema

write_table (CHARACTER VARYING, not null)

the write table’s SQL name; with the two columns above, sql_table’s full key

source_name (CHARACTER VARYING, not null)

the contributing input field’s own declaration file

source_line (INTEGER, nullable)

source line of the input field declaration, 1-based

source_column (INTEGER, nullable)

source column of the input field declaration, 1-based

intent_mutation_write_destination_live (view)

This states the rule and is evaluated on demand. The canonical name intent_mutation_write_destination beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_mutation_write_destination.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_mutation_write_destination.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_mutation_write_destination.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_mutation_write_destination.field_name, whose comment carries what the value means

operation (CHARACTER VARYING, nullable)

the operation of a row of this rule, materialized into intent_mutation_write_destination.operation, whose comment carries what the value means

path (CHARACTER VARYING, nullable)

the path of a row of this rule, materialized into intent_mutation_write_destination.path, whose comment carries what the value means

container_type_name (CHARACTER VARYING, nullable)

the container_type_name of a row of this rule, materialized into intent_mutation_write_destination.container_type_name, whose comment carries what the value means

input_field_name (CHARACTER VARYING, nullable)

the input_field_name of a row of this rule, materialized into intent_mutation_write_destination.input_field_name, whose comment carries what the value means

role (CHARACTER VARYING, nullable)

the role of a row of this rule, materialized into intent_mutation_write_destination.role, whose comment carries what the value means

carrier_role (CHARACTER VARYING, nullable)

the carrier_role of a row of this rule, materialized into intent_mutation_write_destination.carrier_role, whose comment carries what the value means

position (INTEGER, nullable)

the position of a row of this rule, materialized into intent_mutation_write_destination.position, whose comment carries what the value means

column_name (CHARACTER VARYING, nullable)

the column_name of a row of this rule, materialized into intent_mutation_write_destination.column_name, whose comment carries what the value means

destination (CHARACTER VARYING, nullable)

the destination of a row of this rule, materialized into intent_mutation_write_destination.destination, whose comment carries what the value means

write_source_name (CHARACTER VARYING, nullable)

the write_source_name of a row of this rule, materialized into intent_mutation_write_destination.write_source_name, whose comment carries what the value means

write_schema (CHARACTER VARYING, nullable)

the write_schema of a row of this rule, materialized into intent_mutation_write_destination.write_schema, whose comment carries what the value means

write_table (CHARACTER VARYING, nullable)

the write_table of a row of this rule, materialized into intent_mutation_write_destination.write_table, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_mutation_write_destination.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_mutation_write_destination.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_mutation_write_destination.source_column, whose comment carries what the value means

intent_mutation_write_payload

The write surface a walker-driven DML mutation offers: which coordinate writes, with which verb, over which table, through which argument. The relation everything about a generated UPDATE or DELETE statement hangs off, and the first one in this family keyed by the mutation rather than by an input field, because a statement is a coordinate’s and the input fields under it are only its parts. Two verbs, and the pair is a boundary rather than a sample. UPDATE and DELETE are the verbs whose input the generator walks column by column, partitioning it around a key it matches from the catalog, and the two walkers admit exactly the same input shapes; INSERT resolves its input through a different gate that admits a carrier these two refuse, and UPSERT is refused at the verb dispatch before any input is looked at. A relation covering all four would have to carry the gate as a column, and the two that share one gate are the two this is about. Three facts decide the population and all three are the argument’s own rather than any field’s, which is the line this relation draws and the reason it can fold them into an absence at all. A @mutation field takes exactly one argument and that argument’s type is an input object: two arguments, or one that is a scalar, is not a payload at all rather than a payload with something wrong in it. A @condition on that argument is refused outright. And multiRow: true on UPDATE is refused, the broadcast reading being a DELETE’s alone, where a DELETE carries the flag through as the arm that opts out of needing a key. What is deliberately not folded in is the per-field admissibility, which is a different kind of fact: a list-typed carrier, an @condition on an input field, an unbound field, a condition-owned field and a carrier whose value reaches its row only through a join are each a located refusal at a coordinate an author can be pointed at, and turning them into this relation’s absence would replace five diagnostics with one silence at the wrong coordinate. Those belong at the input-field grain, beside the roles that name them, and a consumer assembling a statement reads them there and refuses the whole payload itself. So a row here says the surface exists, not that every field on it is admissible. Two further gates are the return type’s and are equally not here: that a DML mutation returns ID, the written @table type, or a single carrier payload, and that a list-shaped input demands a list-shaped return. Both are refusals about the shape of what comes back, and this relation is about what goes in. Where the write table comes from is the scope relation’s answer read through the verb, and the reading differs between the two verbs because the classifier’s does. An UPDATE derives its target from the return, its own @table type or its carrier payload’s data channel, and falls to a written @mutation(table:) where the return names nothing; those are that relation’s first three rungs in that order, so taking whichever it ranked first is the classifier’s precedence transcribed rather than a second copy of it. A DELETE has no return-derived rung at all, the deleted row’s type being unreturnable, so only the written spelling answers and this relation demands that basis. The participant arm is excluded under both verbs: a write is one statement and a coordinate resolving one table per branch is not one. The multi_row column is the DELETE arm’s own fork and is carried rather than filtered on, because a consumer needs it: with it the walker admits an input covering no key and broadcasts, without it that input is a refusal, and the same two columns therefore describe a statement that deletes one row and one that deletes many. Absence is a @mutation coordinate that offers no such surface, which is every INSERT and UPSERT, every DELETE naming no table, every mutation whose argument shape is refused, and an UPDATE spelling multiRow: true. Materialized: this relation is a table refilled from intent_mutation_write_payload_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from graphitron_mutation

type_name (CHARACTER VARYING, not null)

the type declaring the mutation field, which is a root operation type in every shape the generator emits and is not required to be one here

field_name (CHARACTER VARYING, not null)

the mutation field; with the type, the coordinate whose statement this row describes, and this relation’s grain, one row per writing coordinate

operation (CHARACTER VARYING, not null)

the verb as the author wrote it, UPDATE or DELETE, those being the two the walkers drive. Carried from graphitron_mutation unchanged and not narrowed to an enum here, on the open-column rule the capture relation states

multi_row (BOOLEAN, not null)

whether @mutation(multiRow: true) is written, with the omitted spelling read as false. Meaningful on DELETE alone, where it is the opt-in to a statement that identifies no single row; an UPDATE carrying it has no row here at all, so this column is false on every UPDATE by construction rather than by a rule a reader has to remember

argument_name (CHARACTER VARYING, not null)

the sole argument carrying the payload; the name a consumer reads a wire value out of and the name an occurrence path under this coordinate roots at

argument_type_name (CHARACTER VARYING, not null)

the argument’s named input object type, the type whose fields the payload is assembled from. Not part of the grain, the argument being sole

argument_list (BOOLEAN, not null)

whether the argument is list-shaped, which is the bulk form: one statement over several payload rows rather than one. Carried and not filtered on, the cardinality being the emitter’s fork and not an admissibility question here

write_source_name (CHARACTER VARYING, not null)

the write table’s catalog partition, the first column of the sql_table key this row names

write_schema (CHARACTER VARYING, not null)

the write table’s SQL schema

write_table (CHARACTER VARYING, not null)

the write table’s SQL name; with the two columns above, sql_table’s full key. Also the table every input field under this argument is classified against, which is what makes this the join key into the input-field family rather than only a fact about the statement

source_name (CHARACTER VARYING, not null)

the SDL file the @mutation application was captured from; the position a refusal about this statement would carry

source_line (INTEGER, nullable)

source line of the @mutation application, 1-based

source_column (INTEGER, nullable)

source column of the @mutation application, 1-based

intent_mutation_write_payload_live (view)

This states the rule and is evaluated on demand. The canonical name intent_mutation_write_payload beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_mutation_write_payload.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_mutation_write_payload.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_mutation_write_payload.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_mutation_write_payload.field_name, whose comment carries what the value means

operation (CHARACTER VARYING, nullable)

the operation of a row of this rule, materialized into intent_mutation_write_payload.operation, whose comment carries what the value means

multi_row (BOOLEAN, nullable)

the multi_row of a row of this rule, materialized into intent_mutation_write_payload.multi_row, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_mutation_write_payload.argument_name, whose comment carries what the value means

argument_type_name (CHARACTER VARYING, nullable)

the argument_type_name of a row of this rule, materialized into intent_mutation_write_payload.argument_type_name, whose comment carries what the value means

argument_list (BOOLEAN, nullable)

the argument_list of a row of this rule, materialized into intent_mutation_write_payload.argument_list, whose comment carries what the value means

write_source_name (CHARACTER VARYING, nullable)

the write_source_name of a row of this rule, materialized into intent_mutation_write_payload.write_source_name, whose comment carries what the value means

write_schema (CHARACTER VARYING, nullable)

the write_schema of a row of this rule, materialized into intent_mutation_write_payload.write_schema, whose comment carries what the value means

write_table (CHARACTER VARYING, nullable)

the write_table of a row of this rule, materialized into intent_mutation_write_payload.write_table, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_mutation_write_payload.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_mutation_write_payload.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_mutation_write_payload.source_column, whose comment carries what the value means

intent_mutation_write_refusal (view)

Why an UPDATE the walker admitted field by field is refused anyway, once the matched key has partitioned its columns. The third of three refusal relations over one statement and the last in the order the build reaches them: whether each field is admissible at all is intent_mutation_payload_refusal’s and is collected before any key is matched, whether the admitted remainder pins a row is the matched key’s UNCOVERED verdict, and what is left is what only the partition can see. A consumer assembling an UPDATE reads all three and stops at the first that answers, in that order. The domain is UPDATE alone, and that is the whole reason these causes exist. A DELETE has no assignment half: every admitted column of one is a predicate, so there is no boundary for a carrier to straddle into, no assignment for two writers to collide over, and nothing that must be non-empty. Four causes in three stages, and the stage is what makes the ranking load-bearing rather than cosmetic. The walker collects a stage’s refusals without short-circuiting and returns at the end of it, so a cause from a later stage on the same coordinate is not merely unreported: it would have been computed over a partition an earlier refusal made the walker abandon. This relation therefore keeps, per coordinate, only the causes of the first stage that has any. The first stage carries the two straddles and reports them together, an author fixing one of them meeting the other. MIXED_CARRIER_KEY_MEMBERSHIP is a carrier of the row’s own columns with a column on each side of the key: half of it is the identity the statement finds the row by and half is a value it writes, which is moving the row rather than updating it. NULLABLE_STRADDLING_REFERENCE is a cross-table reference in the same position, where the split itself is legitimate and the spelling is not, clearing a nullable pointer writing half a foreign key and leaving the other half where the predicate put it. A self-referencing foreign key appears under neither, routing wholly to the assignment half before the boundary is consulted. The second stage carries PLAIN_COLUMN_COLLISION, two plain carriers assigning one column, which would silently last-write-win; an overlap one of whose writers decodes its value is admitted instead and reconciled at runtime by the agreement check, which is why the cause is about plain writers rather than about writers. The third carries NO_SET_FIELDS, an UPDATE every column of which is the key it filters on, which is structurally ill-formed rather than a no-op. Where a row is located varies by cause and so do two of its columns, which is the shape of the underlying errors rather than an unfilled slot. A straddle is a fact about one occurrence and names it with no column. A collision is a fact about one column and names every occurrence writing it; the walker’s own diagnostic quotes two of them, which is an artefact of the order it built the assignment half in rather than a fact about the payload, so this relation names the contributors and leaves the choice to whoever renders one. An empty assignment is a fact about the statement and names neither, and its position is the @mutation application’s rather than any field’s. Absence is an UPDATE whose partition the walker accepts, every DELETE, and every coordinate one of the two earlier refusals already answers for.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the write payload

type_name (CHARACTER VARYING, nullable)

the type declaring the refused mutation field

field_name (CHARACTER VARYING, nullable)

the mutation field whose statement this row refuses; with the type, the coordinate intent_mutation_write_payload is keyed by

cause (CHARACTER VARYING, nullable)

which gate refused, in a closed vocabulary of four: MIXED_CARRIER_KEY_MEMBERSHIP and NULLABLE_STRADDLING_REFERENCE from the partition stage, then PLAIN_COLUMN_COLLISION, then NO_SET_FIELDS. Only the causes of the first stage with any appear for a coordinate. A new refusal in the UPDATE walker is a new value here rather than a silence

path (CHARACTER VARYING, nullable)

the occurrence path the refusal is located at; NULL exactly on NO_SET_FIELDS, which is about the statement and has no occurrence to point at

container_type_name (CHARACTER VARYING, nullable)

the input object type the located field is declared on; NULL together with the path

input_field_name (CHARACTER VARYING, nullable)

the located field’s name within that container; NULL together with the path

column_name (CHARACTER VARYING, nullable)

the column two plain carriers both assign; NULL on every cause but PLAIN_COLUMN_COLLISION, a straddle being a fact about a carrier rather than about one of its columns

write_source_name (CHARACTER VARYING, nullable)

the catalog partition of the table the write targets

write_schema (CHARACTER VARYING, nullable)

the write table’s SQL schema

write_table (CHARACTER VARYING, nullable)

the write table’s SQL name; with the two columns above, sql_table’s full key

source_name (CHARACTER VARYING, nullable)

the declaration file a diagnostic would point at, which is the located field’s own on the three located causes and the @mutation application’s on NO_SET_FIELDS

source_line (INTEGER, nullable)

source line of that declaration, 1-based

source_column (INTEGER, nullable)

source column of that declaration, 1-based

intent_name_matched_key_pair (view)

How a hop out of a table-valued function’s result is keyed: for every function result and every table with a primary key, that key’s columns paired with the function’s own columns of the same name. A function result declares no foreign key, so a join leaving one has no constraint to read and the only rule available is the column name, which is the rule the generator applies at both of the seats that leave one. Catalog only, and deliberately so. Which two tables a hop actually connects is a question about a schema, and this relation answers the question underneath it: whether those two tables can be keyed to each other at all. That is why it carries no graph partition and gates on no directive, leaving the graph scope to its consumers exactly as intent_class_member_slot leaves its own to store_graph_source, and it is what lets one relation serve consumers that find their endpoints in different places. Matching is case-insensitive on the column name, as the resolver compares them. Both names are catalog values, so neither side is folded for this comparison’s sake: the function’s column carries a fold because an authored reference meets it elsewhere, and the key column reaches the same fold through the foreign key sql_constraint_column already declares to sql_column. That is the schema’s rule for a comparison inside one family, and it is why this view joins a relation it appears not to need. The match is against the arrival’s primary key alone; a unique constraint is not a candidate here, the generator matching primary-key columns and nothing else. A shortfall is rows rather than absence: every key column of the arrival gets a row whether or not the function exposes it, so a consumer keying a join demands unmatched_columns = 0 and a consumer reporting why it cannot names the columns whose from_column is NULL, which is what the diagnostic at either seat has to say. That is the discipline the ambiguity columns state, applied to a match that came up short rather than to one that came up plural. The pairs carry the key’s own position because a consumer building a key tuple has to build it in the key’s order, and a set would send it back to the constraint to recover one. Nothing here says a pair is meaningful: two tables that name-match are not thereby connected, and every consumer reaches this relation already holding the two ends from somewhere that does say so.

Columns
from_source_name (CHARACTER VARYING, nullable)

the departing function result’s catalog partition. Separate from the arrival’s rather than shared, because the consumers resolve their two ends independently and a graph reading two jOOQ sources can reach a table in either; the pairing is a comparison of column names, and names do not stop matching at a partition boundary

from_schema (CHARACTER VARYING, nullable)

the departing function result’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing function result’s SQL name. With the two columns above this is sql_table’s full key, and table_type is FUNCTION on it by construction

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name; a table with a primary key, one without having nothing to name-match and contributing no rows at all

position (INTEGER, nullable)

the key column’s position within the arriving table’s primary key, carried from sql_constraint_column; the order a consumer building the key tuple has to build it in

to_column (CHARACTER VARYING, nullable)

the arriving table’s primary-key column at this position: the target side of the pair, and the column a diagnostic names when the function does not expose it

from_column (CHARACTER VARYING, nullable)

the function result’s column of the same name, spelled as the function spells it, which is the source side of the pair. NULL where the function exposes no column of that name, which is the shortfall this relation states as a row rather than as a missing one

unmatched_columns (INTEGER, nullable)

how many of the arriving key’s columns this function does not expose; 0 on a pairing a consumer can take whole. Stated as a column rather than left to each reader’s count, for the reason the arity columns elsewhere are: whether the pairing is total decides the reading, a consumer keying a join demanding 0 and a consumer explaining a refusal reading the rows behind a number above it

intent_node_id_decode (view)

How one decoding @nodeId instruction is carried out: one row per instruction and use site, naming the destination that receives the decoded tuple. An instruction with no row here was not carried out, and absence is therefore never a message but the membership condition a defect view is keyed on, which is what keeps a resolution and a rejection from restating one fact. The reduction this relation performs is the whole of the junction-table case. A decode whose every key position lifted to a column of the row’s own table binds locally on a tuple of that table; one where any position did not binds the node type’s own key columns on the node type’s own table inside a correlated EXISTS; and a chain through a junction table is the second because its lift contributes no local column, not because anything rejects it. Those were one conjunct in the resolution this replaces, which picked the local shape when the terminal key’s referenced columns were the node key as a multiset, so the remote shape was unreachable for a multi-hop path and a chain that translated a column met a rejection before the question was asked. Here they are a count against a count. Anything short of every position is remote, which is always correct where a tuple predicate is not, and which position failed to arrive is the key-column child’s answer rather than this relation’s. All four destinations, in two arms over populations that are disjoint by construction rather than by a filter either arm applies twice. A decode landing in a Java slot is the slot arm’s, on intent_node_id_decode_slot’s answer, and the table arm excludes exactly that population, because a slot receives the value and the departing table then binds nothing. The arms are not a per-destination decomposition of one query, which the derivation-depth rule forbids: they read different driving relations for different facts, the table arm reducing the key-column child’s lift and the slot arm reading a parameter and the node key’s shape, and neither re-joins the other’s operands. Within the slot arm the record destination is tested first and wins, which is a precedence and is stated as one: a record holds a tuple whatever the key’s arity, so a single-column key reaching the node type’s own record is that record’s row and not a bare column value. The record has to be the node type’s own table’s record, and a slot typed as some other table’s generated record is deliberately no row here rather than falling through to the single-column destination: a record standing for the enclosing input type receives the tuple on its own table’s columns rather than on the argument’s scope table, so its lift departs somewhere this relation’s endpoints do not resolve, and reading it as a single-column slot would bind one value into a row type. The single-column destination requires arity one and then stands aside on either type being unknown, on intent_resolved_node_key_projection’s discipline for the same operands: a parameter no census could type and a key column no catalog could type both resolve here and are carried out on arity alone, with javac as the backstop, because refusing on an operand nobody could read is the silence this family exists to close. A slot whose type is known and disagrees is no row, and so is a composite key at a slot that is not a record; both are the defect view’s to name. An overloaded producer is also no row, this arm requiring one candidate rather than picking a type, which the slot relation’s own comment asks of a reader that needs the type; that leaves such an instruction in neither population, which is a gap in the partition and named as one rather than absorbed here. Population boundary, stated because a hole here reads as a fact everywhere downstream, and the two arms have different ones. The table arm’s rows come from the endpoint population, so an instruction whose departing or arriving table did not resolve unambiguously has no row and is a defect rather than a decode. The slot arm needs no departing table at all, a slot being reached at the root of the use site, and needs the node type’s key to have resolved, which is the one binding it does read. The node type’s key arity is carried rather than counted by each reader, both because a message about a single-valued slot names the count and because it is the operand the single-column destination turns on. Expensive, and the cost is invisible at the call site, which is why it is stated here: this is the deepest derived read in the schema, it reaches most of the targets meta_materialize registers, and one read of it against a real capture has been measured in seconds rather than milliseconds. A reader that wants it takes it once and pairs it on its key, never correlated per row, per the rule under "Derived reads are views, not stored facts". It carries no registration of its own because nothing on the build path reads it yet; the sibling that is read there is intent_node_id_decode_defect, over intent_node_id_decode_slot rather than over this relation.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the instruction

site (CHARACTER VARYING, nullable)

ARGUMENT or INPUT_FIELD, as on the instruction; the OUTPUT_FIELD site encodes and is answered by intent_node_id_encode instead

type_name (CHARACTER VARYING, nullable)

the type owning the slot, as on the instruction

field_name (CHARACTER VARYING, nullable)

the slot’s field name, or on ARGUMENT the field the argument sits on

argument_name (CHARACTER VARYING, nullable)

the argument carrying the instruction on ARGUMENT; NULL on INPUT_FIELD, determined by site as on the instruction

path (CHARACTER VARYING, nullable)

the occurrence path this row’s use site is, on INPUT_FIELD; NULL on ARGUMENT. Carried for a reader that wants the descent as rows, never as a join key

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the instruction; with the graph, this relation’s key, and the key its two children carry

node_type_name (CHARACTER VARYING, nullable)

the node type the instruction named, whose key the decode yields; intent_resolved_node_key_column on this name and the graph is the other end of the opaque format, and intent_node_id_decode_column is that key already paired with where each position lands

destination (CHARACTER VARYING, nullable)

what receives the decoded tuple, in a closed vocabulary of four. OWN_TABLE_COLUMNS: every key position lifted to a column of the row’s own table, so the predicate binds locally on a tuple of it with no join. TARGET_TABLE_COLUMNS: at least one position did not, so the predicate binds the node type’s own key columns on its own table inside a correlated EXISTS, which is the shape a junction chain takes and the shape a non-unique path wants. JOOQ_RECORD: the value descends into a Java slot typed as the generated record of the node type’s own table, which holds the whole tuple. SINGLE_KEY_COLUMN: the value descends into a Java slot that is not such a record and the key is one column, so that column’s value goes in it. The first two are the table arm and the last two the slot arm, and no row here carries the fifth reading a consumer might want, which is that the decode does not happen: absence is that, and the defect view keyed on it says which precondition stopped it

arity (INTEGER, nullable)

how many key columns the node type resolved, counted over intent_resolved_node_key_column on the table arm and read off intent_resolved_node_key_shape on the slot arm; one number reached two ways because the table arm already has one row per key position and counting them costs nothing, where the slot arm has no such child to count. Carried rather than counted per reader for two reasons that are one fact: a refusal at a single-valued slot names this number, and it is the number that decides whether such a slot can carry the instruction at all

intent_node_id_decode_column (view)

Where each value a decode yields lands: one row per position of the node type’s key, carrying that key column and the column on the slot’s own table the value lifts back to, or nothing where no such column exists. The relation site 4b dissolves into. A decode whose every position carries a local column binds locally on a tuple of the row’s own table; one whose positions carry none binds the node type’s own key columns on the node type’s own table inside a correlated EXISTS; and a junction chain is the second because the lift contributes no local column, not because anything rejects it. Those were one conjunct in the resolution this replaces, which picked the local shape when the terminal key’s referenced columns were the node key as a multiset and rejected a chain that translated a column before the question was reached, so the remote shape was unreachable for a multi-hop path. Here they are two facts and the second is a column being null. The lift is a forward walk and not the backward one it reads as. Walking back from the terminal hop is how a reader thinks about it and it has no recursive form; the same fact stated forward does, and it is an invariant carried along the chain: a row says "this column of the departing table is, after this many hops, this column of the table reached". The seed is the first hop’s own pairing, and each step keeps the local column and replaces the arrived one, joining on the next hop’s departing column matching the current arrived one by name. A hop that translates a column is therefore not a rejection and not a special case: the chain for that position simply has nothing to join to and stops, which is exactly what a lift failing means. Matching is by SQL name with the case folded, which is the same comparison the resolution it replaces makes and inherits its reason: two columns of one table are the same column when their names agree, whatever the catalog’s case. The fold is applied once, to the arrival each step records, so every later comparison against it is against a value already folded rather than against a second call; the local column is deliberately left as the catalog spells it, that one being rendered into a join and not matched against anything. Permutation needs no separate treatment either. The terminal arrival is matched against the key column rather than against a position, so a foreign key declared in a different column order from an @node(keyColumns:) list lands each column at the position the key states, and the transposition the key-column relation’s own comment warns about cannot arise from a positional pairing here. A position with several arrivals is several rows, which takes a malformed catalog to produce, and this relation counts nothing and prefers nothing. Total over the endpoint population crossed with the resolved key, which is the property the destination above depends on: every position of every decode has a row, so all-carry and none-carry are readings of a complete set rather than of whatever survived a join. A partial lift is therefore visible as such, and it is a real shape rather than a modelling gap: a terminal hop whose arriving columns cover only part of the node’s key lifts the part it reaches, which a compound key pinned wider than the constraint produces and a reverse hop produces routinely, that hop arriving on the key’s own columns and reaching whichever of the node’s key columns the departure happens to share. No destination vocabulary names that case, and the reduction above treats anything short of every position as binding remotely, which is always correct where a tuple predicate is not; recording it position by position is what lets a diagnostic say which position was the one that did not arrive. A node type resolving no key columns has no rows at all, absence there being the key relation’s own statement that no tier answered rather than anything about this decode.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the endpoint relation

site (CHARACTER VARYING, nullable)

ARGUMENT or INPUT_FIELD, as on the endpoint relation

type_name (CHARACTER VARYING, nullable)

the type owning the slot, as on the endpoint relation

field_name (CHARACTER VARYING, nullable)

the slot’s field name, as on the endpoint relation

argument_name (CHARACTER VARYING, nullable)

the argument on ARGUMENT; NULL on INPUT_FIELD, as on the endpoint relation

path (CHARACTER VARYING, nullable)

the occurrence path on INPUT_FIELD; NULL on ARGUMENT, as on the endpoint relation, and carried for a reader that wants the descent rather than as a join key

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the endpoint relation; with the graph and the position, the key. The whole decode family keys on this pair, for the reason the hop relation states: the five coordinate columns are the same key in parts, two of them nullable by site, so joining on them costs four null-safe disjunctions and yields a predicate no plan can use

node_type_name (CHARACTER VARYING, nullable)

the node type the instruction named, carried from the endpoint relation; the type whose key this row is a position of, and what a reader over these rows alone needs in order to say which key it is looking at

position (INTEGER, nullable)

the 0-based position within the node type’s key, carried from intent_resolved_node_key_column; the order the decode returns values in, so a tuple predicate binds this row’s local column against the value at this position

tier (CHARACTER VARYING, nullable)

which population answered for the key column, carried from intent_resolved_node_key_column so a reader learns whether the key was pinned in SDL, stated by the generated model, or the bound table’s primary key without joining back. Provenance, and what a message naming a key column stands on

key_column_name (CHARACTER VARYING, nullable)

the node type’s key column at this position, as the winning tier spells it. What the decode yields a value for, and what a remote binding puts the value against on the node type’s own table

local_column_name (CHARACTER VARYING, nullable)

the column on the slot’s own table this position lifts back to, spelled as the catalog spells it, or NULL where the walk reached no such column. The whole discriminator of the two table destinations: every position carrying one is a local tuple predicate, none carrying one is a correlated EXISTS on the node type’s own table. NULL is a stated absence rather than a missing value, and the site is what determines it in the sense the nullable-by-kind discipline allows: on the identity navigation it is the key column itself, on a lifting chain the column the chain reached, and on a translating chain nothing, which is a rule about the navigation rather than an unfilled slot

intent_node_id_decode_defect (view)

What is wrong with a decoding @nodeId instruction whose value reaches a Java parameter and which the decode declined to route there: one row per refused instruction and use site, in a closed verdict vocabulary of two, over the slot relation and the node key’s shape alone. The rejections that close the last silence this directive had, where an author annotated an argument @nodeId, the walk’s type gate stood aside because a decoded value and the ID’s coercion output never meet, and the wire string then reached the consumer’s parameter with nothing in the build saying a word. Written in one pass with the verdict picked by a CASE rather than one UNION ALL arm per verdict, for the reason the fact model states about inline multiplicity: the two verdicts read the same two driving relations for the same two facts, so an arm each would name both a second time to say something one predicate already decides. Population, and it is the whole design rather than a scoping convenience: these are the slot rows the pair-grain argMapping family cannot see, and intent_node_id_decode_slot.carrier already names them. A MAPPED_PARAMETER slot at an argument site is an argMapping pair whose bound leaf is that @nodeId argument itself, so intent_argmapping_projection_defect judges both of these facts there already, BARE_NODE_ID for the arity and KEY_COLUMN_TYPE_MISMATCH for the type disagreement, each keyed on the entry the author wrote and each with a remedy naming it. Restating them here would be a second copy of a shipped rejection with a precedence between the two, which is how one family ends up with two answers that agree until one changes. NAMED_PARAMETER is the carrier no pair exists for, which the slot relation calls the coordinate at which the wire format reached consumer code unread, and judging it is the whole of what this relation adds. The input-field site draws no row, and that is the population’s stated edge rather than an omission. There the parameter receives a container and the decoded value goes to a member of it, so the one destination that resolves is the node type’s own record and everything else wants the walk into the class the slot relation deliberately does not perform. Comparing a container’s type against a key column’s is not an author error and a refusal naming both would be asking for a parameter the author was right to declare, so the shape is owed an emitter rather than a verdict. Which verdict fires is the key’s arity and nothing else, which is why one CASE decides it. Above one column there is nowhere for the second value to go, a parameter holding one; at one column the two types are compared. Both are the author’s to fix in one line of their own signature, so neither is a deferral and no arm here fails while promising an emitter later. The type verdict fires only where both operands are known, which is intent_resolved_node_key_projection’s discipline for the same comparison and is load-bearing rather than inherited wording: a key column no catalog could type and a parameter no census could type both leave the decode to be carried out on arity alone with javac as the backstop, because refusing on an operand nobody could read is the silence this family exists to close and not a second one to open. The arity verdict reads the slot’s type too, and reads it as an absence rather than as a value: what it needs is whether the slot is the tuple’s own row type, and a parameter position naming no class is a primitive or a type variable, neither of which is a generated record, so a composite key still refuses at a parameter the census could not type. That is not a verdict fabricated from a missing fact; the operand is the row type’s identity and the absence answers it. There is no accept line and no population filter of its own, on intent_authored_claim_conflict’s settled terms: the build-error surface joins the classification domain, only an emitted coordinate being able to fail a build, and the editor’s diagnostic arm reads the rows ungated, a coordinate nothing reaches being where an author most needs the signal. Absence is therefore not a message here either. An instruction with a row in neither this relation nor its direction’s resolution relation is either a shape the model does not yet account for or a coordinate another family refuses, and both lists are enumerated rather than left to be discovered. Owed an emitter: every input-field slot above, and a slot the value lands inside. Refused elsewhere: an overloaded producer, whose several candidate slots are a reference the schema walk rejects by name before any of this is read, so declining to pick here leaves no silence; and a departing or arriving table that did not resolve, which the walk likewise refuses on its own. There is no message column, the closed vocabulary plus the witness columns being the fact base and the prose belonging with the consumer that composes it.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the slot relation

site (CHARACTER VARYING, nullable)

the instruction’s site, carried from the slot relation; ARGUMENT throughout today, the input-field site being outside this relation’s population for the reason the view comment states. Carried rather than dropped as a constant because the shape that admits it is owed an emitter rather than excluded on principle, and a row shape that already has the column will not change when it lands

type_name (CHARACTER VARYING, nullable)

the type owning the field the refused argument sits on, as on the instruction

field_name (CHARACTER VARYING, nullable)

the field the refused argument sits on; with the type above, the coordinate a located error attaches to

argument_name (CHARACTER VARYING, nullable)

the argument carrying the instruction, always present on this relation’s one site

path (CHARACTER VARYING, nullable)

the occurrence path the use site is on the input-field site; NULL throughout today, that site drawing no row here

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the instruction; with the graph, this relation’s key, and what a consumer joins on to reach the instruction or the slot

node_type_name (CHARACTER VARYING, nullable)

the node type the instruction named, whose key the slot cannot take; the name a refusal quotes, and the join key to intent_resolved_node_key_column for the columns themselves

verdict (CHARACTER VARYING, nullable)

which precondition stopped the decode, in a closed vocabulary of two. KEY_ARITY_EXCEEDS_SLOT: the node type’s key is several columns and the parameter holds one value, so the refusal names the type and the count. KEY_COLUMN_TYPE_DISAGREEMENT: the key is one column and the Java type it binds as is not the parameter’s, so the refusal names both types and the column. Decided by the arity alone, which is why the two are one pass over one population rather than two arms

arity (INTEGER, nullable)

how many columns the node type’s key has, read off intent_resolved_node_key_shape rather than counted here. The operand the verdict is chosen by, and the number the arity refusal quotes

key_column_name (CHARACTER VARYING, nullable)

at arity one, the column whose value the parameter would have received, as the winning tier spells it; NULL above one by the key’s shape, where there is no single column to name and the arity is what the message is about

column_java_type (CHARACTER VARYING, nullable)

at arity one, the fully qualified Java type jOOQ binds that column as: the left operand of the disagreement, and never NULL on a type-verdict row, the verdict requiring it. NULL on an arity-verdict row, where the key has no single column

slot_java_type (CHARACTER VARYING, nullable)

the fully qualified Java type the parameter takes, at the root of its declared type, carried from the slot relation. The right operand of the disagreement and never NULL on a type-verdict row. NULL is possible on an arity-verdict row and means the census read no class at that position, a primitive or a type variable, which is not the node type’s generated record and is why such a row still refuses

param_name (CHARACTER VARYING, nullable)

the parameter’s own name in Java, which on this relation’s one carrier is the argument’s own name, that name match being how the slot was found. What a message names so an author can find the signature to change

root_type_name (CHARACTER VARYING, nullable)

the type owning the field whose producer method declares the parameter, carried from the slot relation; equal to type_name on this relation’s one site, and carried all the same so a message reads the same way when the input-field site joins the population

root_field_name (CHARACTER VARYING, nullable)

the field whose producer method declares the parameter, on the same terms as the type beside it

root_argument_name (CHARACTER VARYING, nullable)

the argument the descent starts at, equal to argument_name on this relation’s one site

source_name (CHARACTER VARYING, nullable)

the SDL file the instruction was captured from, carried through the slot relation so a located error needs no join to the population

source_line (INTEGER, nullable)

source line, 1-based per the graphql-java convention

source_column (INTEGER, nullable)

source column, 1-based per the graphql-java convention

intent_node_id_decode_endpoint (view)

Where a decode starts and where it has to arrive: for every slot carrying the @nodeId instruction on a decoding site, the table the slot’s own predicate binds on and the table the named node type’s keys live on. The relation the decode’s hop child, its key-column child and the destination over them all read, and it exists because those three would otherwise each resolve the same two tables: the destination is a reduction over the key-column child, the key-column child walks the hops, and the hops need a departure, so the endpoints have to be stated once below all three rather than recomputed inside each. Decoding sites only, which is the direction rule stated as a population rather than as a column: an output field encodes and the two input-side sites decode, so this relation’s WHERE clause is where the direction lives and no reader switches on one. The departure is intent_argument_scope_table’s answer at the consuming argument, which for an argument is its own coordinate and for an input field is the coordinate at the head of its occurrence path, both reached in one pass over the population; that answer is one table per branch where the consuming field returns a multi-table polymorphic container, so such a slot has one endpoint pair per branch and the decode is stated once per branch, which is what the resolver does with it; the two would be a union arm each and each would name the instruction relation again, which is the multiplicity the fact model’s own measurements warn about, so the occurrence path joins outer and the coordinate is picked by COALESCE. The arrival is the node type’s resolved binding, demanded unambiguous for the reason the departure is: two candidate tables are two different key tuples, and a decode against a table the author never named is worse than a decode that does not resolve. The navigation column is the whole reading this relation adds beyond the two tables, and it is a closed vocabulary of three. SAME_TABLE is own-row identity: the slot supplies encoded ids of the very rows it binds on, so the keys land on the row’s own key columns and there is nothing to walk. AUTHORED_PATH is an @reference the author wrote, whose hops the reference-target views resolve, one such view per site. DISCOVERED_KEY is neither written nor identity, where the resolution is the one foreign key declared on the departing table that reaches the arriving one. A fourth value stood here and no longer does. UNRESOLVED_PATH named an input field carrying its own @reference, whose path departs an input type that binds no table, and it existed because no relation walked such a path: the two reference-target views of the time departed from a field’s own binding and from an argument’s scope, and an input field has neither. The value was a statement that the question could not be asked, kept as a value rather than an absence so a consumer could not read it as a chain that legitimately lifted nothing. The input-field walk now exists, departing from the table the consuming field hands the expansion, so the same path resolves the same way an argument’s does and the shape is an AUTHORED_PATH like any other. What the retired value protected against is worth keeping in view, because the protection is now structural rather than nominal: an empty hop set still means own-row identity under one navigation and a chain that stopped under another, and the hop relation states which.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the instruction

site (CHARACTER VARYING, nullable)

ARGUMENT or INPUT_FIELD, as on the instruction; the OUTPUT_FIELD site is absent by construction, an output field encoding rather than decoding

type_name (CHARACTER VARYING, nullable)

the type owning the slot, as on the instruction

field_name (CHARACTER VARYING, nullable)

the slot’s field name, or on ARGUMENT the field the argument sits on

argument_name (CHARACTER VARYING, nullable)

the argument carrying the instruction on ARGUMENT; NULL on INPUT_FIELD, determined by site as on the instruction

path (CHARACTER VARYING, nullable)

the occurrence path this row’s use site is, on INPUT_FIELD; NULL on ARGUMENT. With the four columns above this is the key, and it is the key the two children carry

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the instruction so a message needs no second join

node_type_name (CHARACTER VARYING, nullable)

the node type the instruction named, whose key columns the decode yields; intent_resolved_node_key_column on this name and the graph is the other end of the opaque format

navigation (CHARACTER VARYING, nullable)

how the decode reaches the arriving table, in a closed vocabulary of three: SAME_TABLE for own-row identity with nothing to walk, AUTHORED_PATH for an @reference the author wrote, DISCOVERED_KEY for the one foreign key declared on the departing table that reaches the arriving one. The column the hop child’s arms are disjoint on. A fourth value, UNRESOLVED_PATH, named an input field’s own @reference back when no relation walked one, and it is retired rather than merely unused: the input-field reference walk exists, so such a path is an AUTHORED_PATH and a reader switching on the retired value would be switching on a population that is now empty

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition: the table the slot’s predicate binds on, which is the argument’s scope table at its own site or at the head of its occurrence path

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition: the node type’s own resolved binding, the table its key columns sit on

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name; equal to the departing one exactly on the SAME_TABLE navigation, which is how that value is decided rather than a coincidence a reader has to check

intent_node_id_decode_hop (view)

The foreign-key hops a decode traverses from the slot’s own table to the node type’s, one row per hop in authored order. The ordinal-keyed child of intent_node_id_decode_endpoint, following the parent-plus-steps shape intent_input_occurrence_path and its step relation already use, so a reader takes the path as rows in order rather than parsing a serialized one. Two populations reach it and the endpoint relation’s navigation column is what tells them apart, so they are disjoint by construction and not by a predicate stated twice. An authored path contributes the hops a reference-target view resolved, and there are two such views because there are two decoding sites: an argument’s path departs from the argument’s own scope table and an input field’s from the table its consuming field handed the expansion. The argument-site view came first, authoring it being that work’s stated prerequisite, and the input-field one closed the shape this relation once had to name as unwalkable. Which of the two answers is decided by the site rather than by trying both: each is joined under its own site predicate and the columns are read with COALESCE over the pair, so a row can only ever have come from the view its site names. An unwritten one contributes the single foreign key declared on the departing table that reaches the arriving one, which is the resolution the classifier performs where nothing was written, and it is stated here rather than deferred to intent_field_reference_discovery because that relation answers for a field’s two endpoints and these two endpoints are a different pair: the departing table is the argument’s scope and the arriving one is the node type’s, neither of which is the field’s named type in the general case. Exactly one such key is demanded, which is the classifier’s own arity: two keys are two different predicates and picking one would filter on a relationship the author never named. Written as one pass with the columns picked by CASE rather than as one union arm per navigation, so the endpoint relation is named once; its subtree is the deepest thing under here and a second naming of it would dominate the read, which the fact model has measured on a comparable tree. One navigation contributes nothing and means something by it. SAME_TABLE has no hops because there is nothing to walk, the keys landing on the row’s own key columns, so an empty hop set at that navigation is the answer rather than a failure. A second such navigation stood beside it and is retired: UNRESOLVED_PATH had no hops because no relation resolved an input-field path’s terminal, and it was a named value precisely so a consumer could not read that silence as the identity one. The input-field walk exists now, so those paths contribute hops like any other authored path and the distinction the value carried is no longer one this relation has to make. Absence at the other two navigations is a chain that stopped: the reference-target view carries only the elements it could show the chain reaches, and the discovery arm carries nothing where no single key connects the pair. A hop whose via is NAME_MATCH joins on no foreign key at all and carries a NULL constraint; such a step is refused upstream on a @nodeId path, and it is a row here because it is a hop the path resolved, the refusal being a consumer’s reading rather than this relation’s.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the endpoint relation

site (CHARACTER VARYING, nullable)

ARGUMENT or INPUT_FIELD, as on the endpoint relation

type_name (CHARACTER VARYING, nullable)

the type owning the slot, as on the endpoint relation

field_name (CHARACTER VARYING, nullable)

the slot’s field name, as on the endpoint relation

argument_name (CHARACTER VARYING, nullable)

the argument carrying the instruction on ARGUMENT; NULL on INPUT_FIELD, as on the endpoint relation

path (CHARACTER VARYING, nullable)

the occurrence path on INPUT_FIELD; NULL on ARGUMENT, as on the endpoint relation. Carried for a reader that wants the descent as rows rather than as the one string beside it, and no longer part of the key

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the endpoint relation. With the graph and the position below, the whole of this relation’s key, and that is why it is here rather than only on the parent: the five coordinate columns above are the same key spelled in parts, two of them nullable by site, so a reader joining on them writes four null-safe disjunctions and gets a predicate no plan can use. This column is never NULL and the two sites cannot collide in it, an argument serializing as Type.field(argument) and an input field as an occurrence path of at least one step, so it keys the same rows the parts do. The lift walks this relation’s rows against themselves and that walk is the reader the collapse was measured on

position (INTEGER, nullable)

the hop’s 0-based position along the path, in authored order; always 0 on a discovered key, that arm resolving one hop and never a chain. Contiguous from 0 up to wherever the chain stopped, which is the reference-target view’s own property carried through

via (CHARACTER VARYING, nullable)

which arm resolved the hop: KEY, TABLE or NAME_MATCH carried from the reference-target view where the author wrote the path, DISCOVERED where nothing was written and the single connecting key answered. A closed vocabulary of four, and what a reader asks to learn whether every hop is a foreign key at all, a NAME_MATCH hop joining on none

from_source_name (CHARACTER VARYING, nullable)

the departing table’s catalog partition: the slot’s own table at position 0, the previous hop’s arrival after that

from_schema (CHARACTER VARYING, nullable)

the departing table’s SQL schema

from_table (CHARACTER VARYING, nullable)

the departing table’s SQL name

to_source_name (CHARACTER VARYING, nullable)

the arriving table’s catalog partition; the node type’s own table at the terminal hop, an intermediate table before it

to_schema (CHARACTER VARYING, nullable)

the arriving table’s SQL schema

to_table (CHARACTER VARYING, nullable)

the arriving table’s SQL name

constraint_name (CHARACTER VARYING, nullable)

the foreign key the hop joins on, written or discovered. Its own sql_referential_constraint key is this name under whichever endpoint declares it, which fk_on_from says. NULL on a NAME_MATCH hop, which joins on no foreign key

fk_on_from (BOOLEAN, nullable)

TRUE when the departing table declares the foreign key, FALSE when the arriving one does; the hop’s direction, and what says which side of the key’s column pairing is the local column. Always TRUE on a discovered key, the discovery demanding a key the departing table declares, which is the classifier’s own rule and not a simplification here. NULL on a NAME_MATCH hop

last_position (INTEGER, nullable)

the greatest position this coordinate’s path reached, so the terminal hop is the row whose position equals this. Carried because the lift the key-column child computes has to know where the chain ends and asking the question outside would name this relation a second time, which is the same reason the reference-target views carry their own arities. The greatest position rather than a count of rows, because the two agree only where the positions are contiguous, and they need not be: a position whose route is ambiguous contributes no hop, so a chain can have a gap, and a count would then point at a position that is not the terminal. Under a gap nothing lifts either way, the walk being unable to cross it, so this is a statement that stays true rather than a behaviour that changes

intent_node_id_decode_hop_column

One hop of a decode path oriented along the walk: for each position of the hop’s foreign key, the column on the table the hop departs beside the column on the table it arrives at. intent_node_id_decode_hop says which key a hop joins on and which end declares it; this relation is that key’s column pairing turned the walk’s way round, so a reader takes departing and arriving without having to know which end the catalog put the key on. That reorientation is the only thing here, and it is worth a relation rather than a CASE at each reader because two readers need it and they would express it differently. The lift the key-column child computes walks these rows forward, and a rendered join reads them as its ON clause. Orientation is fk_on_from’s whole purpose: on a hop whose departing table declares the key the departing column is the key’s own and the arriving one is what it references, and on a reverse hop the two swap. The two branches are disjoint on that column and not on the endpoints, which is what keeps a self-referencing key one pairing rather than two mirrored ones. A hop joining on no foreign key contributes nothing, which is the name-matched element over a function result: it keys by column name and declares no constraint, so there is no pairing to state and the shape is refused above rather than modelled here. The path’s extent travels with the rows, the greatest position being carried through from the parent hop so the terminal hop is identified without naming that relation again, which is the same reason it carries it. Materialized: this relation is a table refilled from intent_node_id_decode_hop_column_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the hop

site (CHARACTER VARYING, nullable)

ARGUMENT or INPUT_FIELD, as on the hop

type_name (CHARACTER VARYING, nullable)

the type owning the slot, as on the hop

field_name (CHARACTER VARYING, nullable)

the slot’s field name, as on the hop

argument_name (CHARACTER VARYING, nullable)

the argument on ARGUMENT; NULL on INPUT_FIELD, as on the hop

path (CHARACTER VARYING, nullable)

the occurrence path on INPUT_FIELD; NULL on ARGUMENT, as on the hop, and carried for the same reason: a reader that wants the descent as rows, never as a join key

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the hop; with the graph, the position and the pair position, the key. The column the lift joins on, for the reason the hop states

position (INTEGER, nullable)

the hop’s own 0-based position along the path, carried from the hop; with the pair position beside it, the use site and the graph, this is the key

pair_position (INTEGER, nullable)

the 0-based position within the hop’s foreign key, the same position on both sides of the pair. The order a tuple predicate over this hop has to preserve, and what makes the walk positional rather than a name lookup that happens to agree

from_column_name (CHARACTER VARYING, nullable)

the column on the table this hop departs: the key’s own column where the departing table declares it, the column it references where the arriving table does

to_column_name (CHARACTER VARYING, nullable)

the column on the table this hop arrives at, the other half of the pair. What the next hop’s departing column is matched against, and at the terminal hop what a node key column is matched against

last_position (INTEGER, nullable)

the greatest position the path reached, carried from the hop; the terminal hop is the one whose position equals this

intent_node_id_decode_hop_column_live (view)

This states the rule and is evaluated on demand. The canonical name intent_node_id_decode_hop_column beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_node_id_decode_hop_column.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_node_id_decode_hop_column.graph_name, whose comment carries what the value means

site (CHARACTER VARYING, nullable)

the site of a row of this rule, materialized into intent_node_id_decode_hop_column.site, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_node_id_decode_hop_column.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_node_id_decode_hop_column.field_name, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_node_id_decode_hop_column.argument_name, whose comment carries what the value means

path (CHARACTER VARYING, nullable)

the path of a row of this rule, materialized into intent_node_id_decode_hop_column.path, whose comment carries what the value means

use_site (CHARACTER VARYING, nullable)

the use_site of a row of this rule, materialized into intent_node_id_decode_hop_column.use_site, whose comment carries what the value means

position (INTEGER, nullable)

the position of a row of this rule, materialized into intent_node_id_decode_hop_column.position, whose comment carries what the value means

pair_position (INTEGER, nullable)

the pair_position of a row of this rule, materialized into intent_node_id_decode_hop_column.pair_position, whose comment carries what the value means

from_column_name (CHARACTER VARYING, nullable)

the from_column_name of a row of this rule, materialized into intent_node_id_decode_hop_column.from_column_name, whose comment carries what the value means

to_column_name (CHARACTER VARYING, nullable)

the to_column_name of a row of this rule, materialized into intent_node_id_decode_hop_column.to_column_name, whose comment carries what the value means

last_position (INTEGER, nullable)

the last_position of a row of this rule, materialized into intent_node_id_decode_hop_column.last_position, whose comment carries what the value means

intent_node_id_decode_slot (view)

The Java parameter a decoding @nodeId instruction’s value descends into, where it descends into one at all, and the type that parameter takes. The relation the decode’s destination forks on first, and the fork is not between two shapes of predicate but between a predicate and consumer code: a slot carrying the instruction never delivers the wire format to a consumer, so where the value reaches Java the departing table the endpoint relation resolved receives nothing and no predicate is emitted from it. What decides that is the root of the use site rather than the instruction’s own coordinate, which is the whole reason this relation is cheap and the reason it is correct. An argument’s value reaches Java when a producer parameter is fed from it; an input field’s value reaches Java exactly when the argument its occurrence path descends from does, the field being one step inside a value handed to that parameter. So both sites ask one question at one coordinate, the occurrence path supplies that coordinate for the input-field site and the instruction is its own for the argument site, and no relation about classes, type backings or class members is read at all. An earlier shape asked instead which class member received the value, and it was both slower by an order of magnitude and answering a question one step past the fork. Two carriers, disjoint by construction. MAPPED_PARAMETER is an argMapping pair whose path binds the root argument itself, which is how a bean or a record is fed the whole argument, and it covers both the pair that stops at the argument and the pair that names a key column beyond it, those being one destination differing only in provenance. NAMED_PARAMETER is the producer method declaring a parameter of the root argument’s own name with no pair on that parameter, which is the match the generator itself makes and the coordinate at which the wire format reached consumer code unread. The absence of a pair on the parameter is what makes the two disjoint, and it is read on the parameter rather than on the argument because a pair redirects a parameter to some other argument and the name match must not then claim it. Presence and type are two facts here and keeping them apart is the one place this relation must not inherit its neighbour’s reading. intent_argmapping_bound_parameter_type has no row where the census cannot type a parameter, and its readers are free to treat that absence as no answer. Here absence means something else: no row is "this decode binds a predicate", so an untypeable parameter arriving as absence would route a value bound for Java to a table predicate that has nothing to bind. Both arms therefore reach the type by outer join and an untypeable parameter is a row with a null type, which is what lets a consumer carry the decode out on arity alone and ask for a type only when it is about to refuse. Ambiguity is rows and nothing is preferred: an overloaded method or a class two classpath entries declare resolves more than one row and candidates says so, on the neighbouring relation’s own terms. Which is why an ambiguous producer reference is not filtered out here, where every other reader of that relation demands one candidate. Demanding one would drop the rows entirely, and a use site with no row here reads as binding a table predicate, so an author whose @service names two overloads would get the wire format bound into SQL on the strength of an ambiguity nobody resolved. Keeping the rows makes that use site a decode with several candidate slots, which a consumer refuses to carry out rather than mistaking for a predicate. The stated limit is one shape, and it is the one this relation’s coordinate choice trades away. An argMapping path that descends into the argument and binds one input field below it (a pair spelled arg.field) hands that one field to a parameter while its siblings still bind predicates, and this relation sees no row for either, its arms asking about the root argument and that path binding something under it. Saying which occurrence path such a pair names is a reconciliation between two decompositions of one descent rather than a join, and until that is stated an input field reached only that way is read as binding a predicate.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the instruction

site (CHARACTER VARYING, nullable)

ARGUMENT or INPUT_FIELD, as on the instruction; the OUTPUT_FIELD site is absent by construction, an output field encoding rather than decoding

type_name (CHARACTER VARYING, nullable)

the type owning the slot carrying the instruction, as on the instruction: the argument’s owning type on ARGUMENT, the input object type on INPUT_FIELD. Not the root coordinate, which is the three columns below

field_name (CHARACTER VARYING, nullable)

the instruction’s field name, or on ARGUMENT the field the argument sits on

argument_name (CHARACTER VARYING, nullable)

the argument carrying the instruction on ARGUMENT; NULL on INPUT_FIELD, determined by site as on the instruction

path (CHARACTER VARYING, nullable)

the occurrence path this row’s use site is, on INPUT_FIELD; NULL on ARGUMENT. Carried for a reader that wants the descent as rows, never as a join key

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, carried from the instruction; with the graph, the key of the instruction this row is about, and what the decode relation joins on

node_type_name (CHARACTER VARYING, nullable)

the node type the instruction named, carried from the instruction so a message about this parameter needs no second join

root_type_name (CHARACTER VARYING, nullable)

the type owning the field the value’s descent starts at: the instruction’s own type on ARGUMENT, the occurrence path’s root type on INPUT_FIELD. The coordinate both arms resolve the parameter against, carried because it is the coordinate a message has to name when the parameter it found is several steps above the slot the author annotated

root_field_name (CHARACTER VARYING, nullable)

the field the descent starts at, on the same terms as the type beside it; the field whose producer method declares the parameter

root_argument_name (CHARACTER VARYING, nullable)

the argument the descent starts at: the instruction’s own argument on ARGUMENT, the occurrence path’s root argument on INPUT_FIELD. Equal to argument_name exactly on the ARGUMENT site, which is how that value is decided rather than a coincidence a reader has to check

carrier (CHARACTER VARYING, nullable)

which rule found the parameter, a closed vocabulary of two. MAPPED_PARAMETER: an argMapping pair binds the root argument, so the parameter it names receives the whole argument. NAMED_PARAMETER: no pair names that parameter and the producer method declares one of the root argument’s own name. Provenance and shape at once, as on the instruction’s basis column, because a refusal has to be able to say how the parameter was found: an author who wrote no argMapping is told about a name match and an author who wrote one is told about their own entry

param_name (CHARACTER VARYING, nullable)

the parameter’s own name in Java, which on both arms is the name the match was made on: the pair’s left side, or the declared parameter name the argument matched

java_type (CHARACTER VARYING, nullable)

the fully qualified binary name of the type the parameter takes, at the root of its declared type. NULL where no census could read it: a consumer compiled without -parameters, a reference resolving no method, a primitive parameter, or a position naming no class. The root and not the peel, deliberately, so that this is the same value intent_argmapping_bound_parameter_type states and a type agreement a projection already performs cannot answer differently depending on which arm found the parameter. A container-typed parameter therefore reports the container, and that a list of node ids is a coherent request rather than a mistake is stated on the leaf relation and is a consumer’s reading, not this relation’s

candidates (INTEGER, nullable)

how many rows this use site resolved, counted over both carriers. One is the ordinary answer; more than one is an overloaded method or a class two classpath entries declare, and this relation distinguishes neither. A reader requiring one type requires this to be one rather than picking, which is the discipline intent_argmapping_bound_parameter_type states for its own version of this column; a reader asking only whether the value reaches Java ignores it

source_name (CHARACTER VARYING, nullable)

the SDL file the instruction was captured from, carried from the instruction. Here for the reason node_type_name is: a refusal about this parameter is located at the slot the author annotated, and a consumer that had to re-join the instruction for its position would name the population relation a second time, which is the multiplicity the fact model measures as dominant

source_line (INTEGER, nullable)

source line, 1-based per the graphql-java convention, carried from the instruction

source_column (INTEGER, nullable)

source column, 1-based per the graphql-java convention, carried from the instruction

intent_node_id_encode (view)

How an output field carrying the @nodeId instruction produces the tuple it encodes. The encoding half of the resolution, and a separate relation from the decode rather than one relation with a direction column, because the two answer different questions and sharing a row shape would leave half the columns nullable by kind: a decode has a destination that receives a tuple and, where that destination is a table, a column correspondence and possibly a join path, while an encode has a source that produces one and never has either. Direction is therefore not a column anywhere; it follows from the site and from which of the two relations answered. Output fields only, which is that rule stated as a population. Two sources, and the discriminator is whether a column tuple is in scope at all. PROJECTED_COLUMNS is everything that encodes today: the field sits on a type some table stands for and nothing overrides how its value is produced, so the key columns are selectable and the encode wraps them at the projection, whether they are the row’s own or reached through an authored path. READ_VALUE is the rest, and it is one source rather than four because the four spellings differ only in the mechanism a value arrives by: an accessor on a backing class, a by-name record read, a typed column off a record, or graphql-java’s own property machinery all hand the generator one value, and the encode applies to what the read yielded. The two conditions that put a field there are a containing type no table stands for, which is what an @error type is, and a field whose value a named producer method returns, which overrides the projection its containing type would otherwise offer. That second condition reads the producer reference and not the method it resolves to, on purpose: an @externalField naming a method the classpath census never saw still means the value is read rather than projected, and asking the resolved relation would have made an unresolvable reference look like a projection, which is the one reading that puts a base64 string where a column belongs. One precondition is stated here and it is arity: a read yields one value, so a node type whose key is several columns cannot be encoded from one, and such a coordinate has no row. The other precondition a READ_VALUE encode has is deliberately not stated here, and the reason is a limit rather than a preference: an encode from a read needs the value to arrive as the key column’s own Java type, and what type the read yields is decided by which of four locator arms the classification chose. Two of the four type nothing at all, and one of the two that do resolves an accessor by a candidate order and a naming rule, which is an algorithm and not a fact this schema holds. So these rows over-claim by exactly the coordinates the schema walk refuses on type, that refusal being where both operands are in hand: the walk loads the backing class through the codegen classloader and reads the catalog for the column. A reader wanting the whole truth about an output field reads the classification’s own verdict beside this relation, and a partial precondition here would be worse than the stated absence, since it would resolve or refuse depending on which arm answered without being able to say which arm that was. A projection has no such limit, the whole tuple being in scope, which is why the arity demand is written once against the source rather than as a blanket filter. Absence is therefore not the message and never should be read as one: an instruction with no row here was not carried out, and which precondition stopped it is the detection stratum’s statement with the operands to make it, on the same terms that keep the candidate and projection relations beside the argMapping family disjoint by construction rather than each re-testing the other’s predicate. Presence is not an emitter, which is the symmetric reading and the easier one to get wrong: a row says where the tuple would come from, and whether the generator carries the encode out at that coordinate is the schema walk’s fact rather than this relation’s. Two shapes here are recognised and deferred rather than emitted, and both are named so neither is left to be discovered: a PROJECTED_COLUMNS row over an authored path that did not collapse into the parent’s own columns, which the walk defers at the reference carrier, and a READ_VALUE row for a field whose value a producer returns, which the walk defers with a message naming the producer directive. Narrowing the population to what emits today would make this relation track emitter maturity, so a shape acquiring an emitter would change rows in a graph whose schema nobody touched, and the two facts a consumer wants apart would be one column again.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the instruction

type_name (CHARACTER VARYING, nullable)

the object type owning the encoding field

field_name (CHARACTER VARYING, nullable)

the encoding field’s name within that type. With the two columns above this is the key: an output field is its own use site, so there is no third component and no path, which is the shape difference from the decode stated as a narrower key

use_site (CHARACTER VARYING, nullable)

the coordinate serialized, carried from the instruction so a message needs no second join; always Type.field here, an output field being its own use site

node_type_name (CHARACTER VARYING, nullable)

the node type whose identity is being encoded, written or inferred. intent_resolved_node_key_column on this name and the graph gives the columns to encode from, in order, and intent_resolved_node_type_id gives the prefix they are encoded under

source (CHARACTER VARYING, nullable)

where the tuple comes from, in a closed vocabulary of two: PROJECTED_COLUMNS where the key columns are selectable at the field’s own site and the encode wraps them at the projection, READ_VALUE where the field’s value arrives through a read and the encode applies to what the read yielded. The column a consumer switches on, and what says whether the arity demand applied

arity (INTEGER, nullable)

how many columns the node type’s key has, counted over the rows intent_resolved_node_key_column already answered with rather than by reading that relation a second time, which is the shape the fact model has measured as dominant on a comparable tree. Always 1 on a READ_VALUE row, that being the precondition; unbounded on a projection. Carried because a consumer emitting the encode needs the width and because a message about a refused sibling coordinate names this number

intent_node_id_instruction

Every slot carrying the @nodeId instruction, and which node type it names. The population the resolution relations and the defect view both partition, and the reason this exists as a relation rather than as each of their own WHERE clauses: the detection is "instructed and not carried out", so an instruction the population misses is a coordinate that stays silent, and a population two readers spell separately is two populations. Three sites, and site is the discriminator every other column’s nullness is determined by, on intent_argmapping_pair’s terms: an argument name where the site is an argument, an occurrence path where it is an input field, and the stated absent bucket elsewhere. Direction is deliberately not a column: an OUTPUT_FIELD encodes and the other two decode, which follows from the site and from which resolution relation answered, so a column would be a third spelling of a fact two relations already carry. The instruction has three authored forms and this relation states five bases over them, because the two inference rules and the two name-carried cases are different rules rather than one rule with cases. They are disjoint rather than ranked, which is what lets this be a plain union with no windowed collapse over it, and the disjointness is by construction: the three directive bases require a captured row and the two name-carried bases require the absence of one, EXPLICIT_TYPE_NAME requires a written typeName: and the two inference bases its absence, and the two inference bases split on the site-and-@reference predicate the manual states them with. Grain is the instruction and its use site. An argument and an output field are their own use site; an input field’s use sites come from intent_input_occurrence_path, so one input field carrying one directive is as many rows as there are coordinates consuming it. That is load-bearing rather than tidy: one input type may be consumed where the target resolves and where it cannot, so a row keyed on the instruction alone would have to pick one answer for two consumers, which is the argument ArgmappingProjectionDefects already makes for its own messages. An input field on an input type nothing reaches produces no occurrence path, so no use site, so no row; that is not a reachability gate but the observation that a decode is "these values go here" and with no consuming coordinate there is no here. Population boundary, stated because a hole here reads as a fact everywhere downstream: an instruction whose named or inferred type resolves to no node type is not a row. Those coordinates already meet a shipped rejection naming the type, so admitting them would put an instruction in the population that neither resolves nor draws either of the defect view’s verdicts, breaking the partition to restate a message. The one shape this relation cannot yet enumerate is an input field carrying its own @reference path: the target views resolve a path from a type’s table binding, an input type has none, and no relation resolves an input-field path’s terminal. Such a slot with an explicit typeName: is a row here like any other; only its bare form is missing, and closing it wants an input-site target view rather than a wider rule here. One further multiplicity comes in through the departure the two inference bases read, and it is the classifier’s own rather than this relation’s: the argument scope those bases resolve against is one table per branch at a field returning a multi-table polymorphic container, so an inferred instruction there names one node type per branch. At a top-level argument that is the per-branch decode the resolver supports outright, each branch decoding ids of its own participant. At a nested input field it is the divergence the resolver rejects, one leaf meaning a different id on each branch, and the two rows carrying two node types are what makes that rejection a detection over this relation rather than a walk check with nothing behind it. Neither is a case in the rules above; both are the departure relation’s grain arriving here, which is why the bases stay five. What those rows do not carry is which branch each came from, and that is this relation’s limit rather than the departure’s. The grain here is the use site and the one table the site’s content binds against, so a use site with two table-bound participants is two rows differing in node_type_name and in nothing else, and no column says which participant resolved which. The pairing can be recovered by joining a row’s node type back to its own table and that table to the participant binding it, and the recovery is not sound in general: two participants over one table, or a node type that is not the participant type itself, each break it. So a reader can see that the branches disagree, which is what makes the rejection at a nested leaf a detection over these rows, and cannot assemble one branch’s decode from them. Only the two bare inference bases reach this shape. A written typeName: resolves on EXPLICIT_TYPE_NAME at every coordinate and is one row here as anywhere else, and a discriminated interface carrying its own @table binds one table for every participant and is likewise one row; the multiplicity is the multi-table container’s alone. Closing it wants a participant-keyed arm at the grain the answer actually has, (graph_name, site, type_name, field_name, argument_name or path, participant type name), and that spelling is stated here once so that a later widening and any reader threading participants outside the store cannot mint two spellings of one key. It is unwritten because one reader asks this question and answers it for itself; the arm is worth having the day a second one asks. What closing it must not reach for is relaxing the single-candidate demand the two inference bases make: the branches are several because the departure is several, and each branch’s own table must still back exactly one node type for the inference to name anything at all. Materialized: this relation is a table refilled from intent_node_id_instruction_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from whichever arm produced the row

site (CHARACTER VARYING, nullable)

which SDL site carries the instruction, in a closed vocabulary of three: OUTPUT_FIELD, INPUT_FIELD, ARGUMENT. The column a consumer switches on, the one that decides the direction, and the one every other column’s nullness is determined by. The two field sites share one captured relation and are told apart by the owning type’s kind, which is how the capture side already tells them apart

type_name (CHARACTER VARYING, nullable)

the type owning the slot: an object type on OUTPUT_FIELD, an input object type on INPUT_FIELD, the argument’s owning type on ARGUMENT

field_name (CHARACTER VARYING, nullable)

the slot’s field name, or on ARGUMENT the field the argument sits on

argument_name (CHARACTER VARYING, nullable)

the argument carrying the instruction on the ARGUMENT site; NULL on the two field sites, determined by site rather than independent of it, which is what makes the nullness a stated rule instead of a missing value

path (CHARACTER VARYING, nullable)

the occurrence path this row’s use site is, on the INPUT_FIELD site; NULL on the other two, whose slot is its own use site. The serialized key of intent_input_occurrence_path, so the use site’s own coordinate and every step of the descent are one join away and nothing here is parsed

use_site (CHARACTER VARYING, nullable)

the consuming coordinate serialized, in intent_argmapping_pair’s vocabulary: Type.field for an output field, Type.field(argument) for an argument, and the occurrence path itself for an input field, that path already being this serialization. Carried because a message needs one string and the components differ by site; those components are columns beside it, so nothing parses this

basis (CHARACTER VARYING, nullable)

which rule stated the instruction and resolved its target, in a closed vocabulary of five disjoint rules. EXPLICIT_TYPE_NAME: @nodeId(typeName: T). CONTAINING_NODE_TYPE: bare @nodeId on a non-@reference object field whose containing type is itself a node, the manual’s inference rule (a). TARGET_TABLE_NODE_TYPE: bare @nodeId whose target comes from a table, the manual’s inference rule (b), demanding exactly one node type over that table. OWN_ID_FIELD: a node type’s own id field with no directive, which is a node ID by construction. TARGET_ID_NAME: a slot named for the target’s own id with no directive, an argument of a node-returning field or an input field consumed against a node-backed table. Provenance and shape at once, which is why it is one column and not two: typeName: is rejected outright on a node type’s own id field, so the forms are not interchangeable and a rejection has to be able to say which one the author wrote

node_type_name (CHARACTER VARYING, nullable)

the node type the instruction names, written or inferred; never NULL, the population being instructions whose target resolved. What the opaque format’s other end is: intent_resolved_node_key_column on this name and the graph gives the key columns in order, and intent_resolved_node_type_id gives the typeId

carries_reference_path (BOOLEAN, nullable)

whether the slot carries an @reference path of its own, read on the captured relation the slot’s site keys: the argument-site steps on ARGUMENT, the field-site steps on the two field sites. Carried because it decides how the instruction navigates to the node type’s table and because two of the bases above are already disjoint on it, so a reader resolving the navigation would otherwise re-derive a predicate this view has already evaluated. It says a path is written and nothing about whether one resolves; where the path resolves to is the reference-target views' answer and a slot whose path reaches nothing is TRUE here all the same

source_name (CHARACTER VARYING, nullable)

the SDL file the instruction was captured from; the directive application’s own position on the three directive bases, and the slot declaration’s on the two name-carried ones, there being no application to locate

source_line (INTEGER, nullable)

source line, 1-based per the graphql-java convention

source_column (INTEGER, nullable)

source column, 1-based per the graphql-java convention

intent_node_id_instruction_live (view)

This states the rule and is evaluated on demand. The canonical name intent_node_id_instruction beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_node_id_instruction.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_node_id_instruction.graph_name, whose comment carries what the value means

site (CHARACTER VARYING, nullable)

the site of a row of this rule, materialized into intent_node_id_instruction.site, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_node_id_instruction.type_name, whose comment carries what the value means

field_name (CHARACTER VARYING, nullable)

the field_name of a row of this rule, materialized into intent_node_id_instruction.field_name, whose comment carries what the value means

argument_name (CHARACTER VARYING, nullable)

the argument_name of a row of this rule, materialized into intent_node_id_instruction.argument_name, whose comment carries what the value means

path (CHARACTER VARYING, nullable)

the path of a row of this rule, materialized into intent_node_id_instruction.path, whose comment carries what the value means

use_site (CHARACTER VARYING, nullable)

the use_site of a row of this rule, materialized into intent_node_id_instruction.use_site, whose comment carries what the value means

basis (CHARACTER VARYING, nullable)

the basis of a row of this rule, materialized into intent_node_id_instruction.basis, whose comment carries what the value means

node_type_name (CHARACTER VARYING, nullable)

the node_type_name of a row of this rule, materialized into intent_node_id_instruction.node_type_name, whose comment carries what the value means

carries_reference_path (BOOLEAN, nullable)

the carries_reference_path of a row of this rule, materialized into intent_node_id_instruction.carries_reference_path, whose comment carries what the value means

source_name (CHARACTER VARYING, nullable)

the source_name of a row of this rule, materialized into intent_node_id_instruction.source_name, whose comment carries what the value means

source_line (INTEGER, nullable)

the source_line of a row of this rule, materialized into intent_node_id_instruction.source_line, whose comment carries what the value means

source_column (INTEGER, nullable)

the source_column of a row of this rule, materialized into intent_node_id_instruction.source_column, whose comment carries what the value means

intent_node_metadata_defect (view)

What is wrong with the node-identity metadata a generated table class stated: one row per defect, over the sql_node_metadata rows and their entries alone. The rows it reads are transcription because a walk read them; this is not, because no walk read the verdict that metadata is malformed. Graphitron’s rule produces it, and every join is inside the jOOQ corpus, which is what makes it a derivation over one corpus rather than a validation smuggled into a crawler. Well-formed metadata is a sql_node_metadata row with no defect rows, and the conjunction is the whole test: no defect rows alone is also what a table publishing nothing at all has, that table having no metadata row to be well-formed. Every defect a table exhibits gets a row, with no first-failing short-circuit, so no evaluation order becomes normative; a reader wanting one message reduces by an ordering it owns. There is no reason-text column, deliberately: the closed defect vocabulary plus the witness columns already stored are the fact base, and message prose belongs with the consumer that composes it. Keyed on the catalog’s own key with no graph partition, as intent_name_matched_key_pair is: the question is about a table, and a graph reaches it the way it reaches any source-keyed fact.

Columns
source_name (CHARACTER VARYING, nullable)

the table’s catalog partition, the first column of the sql_node_metadata key this row is about

table_schema (CHARACTER VARYING, nullable)

the table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the table’s SQL name; with the two columns above, the metadata row this defect is about

defect (CHARACTER VARYING, nullable)

which defect, in a closed vocabulary of ten: TYPE_ID_NOT_DECLARED, TYPE_ID_NULL, TYPE_ID_WRONG_TYPE and TYPE_ID_EMPTY on the type-id constant; KEY_COLUMNS_NOT_DECLARED, KEY_COLUMNS_NULL, KEY_COLUMNS_WRONG_TYPE and KEY_COLUMNS_EMPTY on the key-columns constant; KEY_COLUMN_ENTRY_NULL and KEY_COLUMN_UNRESOLVED on one entry of it. The vocabulary is finer than the reflection probe it will eventually replace, which reports one message per constant however that constant went wrong: the store distinguishes the states because it holds the forms separately, and collapsing them here to match the probe would discard a distinction the rows already carry

position (INTEGER, nullable)

the offending entry’s index in the stated array, on the two per-entry defects; NULL on the eight that are about a whole constant, which is the stated absent bucket rather than a missing value

intent_node_type (view)

Which of a graph’s types are node types: the union of the authored @node population and the inferred one. The store’s answer to the question NodeDeclaration.isNodeType answers live, and the relation every reader of nodehood joins instead of restating the rule. A declaration-level answer, matching that predicate: @node without implements Node still reads as a node here, and rejecting that shape is the classifier’s job rather than this relation’s, since a membership relation that silently dropped a declared node would leave a detection with nothing to detect. The predicate’s declared-wins short-circuit needs no transcription: a UNION dedupes, so precedence dissolves along with the provenance column that would have asked for it, and a reader wanting to know which rule answered reads the arm, both arms being residents in their own right. Inference is a cross-corpus join and lands in the arm that performs it, which is what keeps the SDL crawlers writing rows about the SDL alone.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from whichever arm produced the row

type_name (CHARACTER VARYING, nullable)

the node type; keyed with the graph, one row per node type however many arms answered for it

intent_poly_member (view)

What a polymorphic container holds: one row per member of a union and per implementor of an interface, in an order the container can state. Two populations that answer the same question and neither a special case of the other, so they are separate base tables and this is where they meet, on intent_type_backing’s terms. The container axis is what makes them one relation: a reader asking what a field’s named type resolves to when that type is not an object asks about members, and whether the SDL spelled the membership on the container (a union) or on the member (an implements clause) is the base tables' business, not the reader’s. Position is stated on both arms and means source order on both, but it is authored on only one of them: a union declares its members in one place and graphql_union_member records that ordinal, while an interface’s implementors are declared apart from it and apart from each other, so the position here is derived from where each implementor is written. That derivation is this relation’s and not the SDL’s, which matters to exactly one reader, the mapping-constant fingerprint, whose digest is over an ordered handler list; the walk’s own order for the interface arm is graphql-java’s registration order, which is neither source order nor documented, so an implementor arm’s digest computed from these rows may differ from the walk’s. A source order is the defensible one to state and the disagreement is the walk’s to lose, but nothing has adjudicated that yet and a reader minting a suffix from these rows should know it is choosing.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

container_name (CHARACTER VARYING, nullable)

the polymorphic type holding the member: the union on one arm, the interface on the other

container_kind (CHARACTER VARYING, nullable)

which population answered, a closed two-value domain: UNION for a member listed on a union declaration, INTERFACE for a type whose implements clause names the container. Provenance, and the axis a reader filters on when it means one of them

member_type_name (CHARACTER VARYING, nullable)

the object type the container resolves to; on the interface arm the implementing type, on the union arm the listed member

position (INTEGER, nullable)

source order within the container, 1-based on the interface arm and the union’s own authored ordinal on the union arm. Authored on the union arm and derived on the interface arm, from the implementor’s declaration site with the type name breaking a tie; see the relation’s own note on what that costs a reader fingerprinting an ordered list

intent_producer_cardinality_conflict (view)

Where a field and the method producing its value disagree about how many: one row per producing coordinate whose SDL type is a list whose producer delivers one, or whose SDL type is single where the producer delivers many. A detection the store did not have, and the reason it did not is worth stating, because it is the argument for decomposing a walk into facts at all. The walk this derivation replaces reads the same two cardinalities and uses the comparison as a clause: where they disagree it declines to bind, reading the field as a carrier whose collection feeds an inner list field. So the reading existed and its result was a silence, which is exactly the shape a defect hides in. Stated as its own relation the comparison is observable, and whether a given row is a carrier or an author error is a question a reader can now ask rather than one the walk answered by moving on. Nothing gates on these rows yet. A coordinate whose reference matches several overloads contributes a row per overload that disagrees, on intent_field_producer_method’s terms, since which method the reference means is that relation’s open question and not this one’s to settle. A producer whose declared return names no class at its root has no row here at all rather than a row asserting agreement: the peel it would be compared against does not exist, and a primitive or an array return is a different complaint from a cardinality one.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from intent_field_producer_method

type_name (CHARACTER VARYING, nullable)

the disagreeing coordinate’s owning type

field_name (CHARACTER VARYING, nullable)

the disagreeing coordinate’s field name

declared_via (CHARACTER VARYING, nullable)

SERVICE or EXTERNAL_FIELD, as on intent_field_producer_method; which directive named the method whose cardinality disagrees

source_name (CHARACTER VARYING, nullable)

the producing method’s classpath entry, as on intent_field_producer_method

class_name (CHARACTER VARYING, nullable)

the class declaring the producing method

method_name (CHARACTER VARYING, nullable)

the producing method’s name

descriptor (CHARACTER VARYING, nullable)

the producing method’s raw JVM descriptor, which tells two overloads of one reference apart

field_is_list (BOOLEAN, nullable)

what the SDL says, carried from graphql_field.is_list; always the negation of the column beside it, and carried anyway so a reader learns which way the disagreement runs without joining back

producer_delivers_many (BOOLEAN, nullable)

what the declared return says, carried from intent_declared_type_element.delivers_many; the other half of the disagreement this row reports

intent_resolved_field_claim (view)

The field-grain claim resolution: the authored relation unioned with the inferred rows at coordinates the authored relation does not cover. Masking is this join’s job, never a classifier’s guard, and the anti-join sits at the coordinate grain: any authored claim at a coordinate masks every structural reading there, presence arms included, because a directive whose decode declined still diverted the walk. The projection is the claim key plus tier, no trigger, decoded or witness component, so nothing goes nullable by kind; a reader wanting provenance joins the tier’s own view, and tier is a column precisely so that home is a read rather than a hand-maintained classifier-to-relation mapping. The stratum’s second layer, and what a planning reader eventually joins.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the claim views

type_name (CHARACTER VARYING, nullable)

the claimed field’s owning type

field_name (CHARACTER VARYING, nullable)

the claimed field’s name within the owning type

classifier (CHARACTER VARYING, nullable)

the classification kind the claim is for, the union of the claim views' closed vocabularies

tier (CHARACTER VARYING, nullable)

AUTHORED from the authored view, INFERRED from a classifier view surviving the anti-join; names which relation carries this claim’s provenance

intent_resolved_field_demand (view)

The field-grain demand reduction: one verdict per accounted coordinate of the classification domain, over every field-bearing parent kind (input coordinates resolve EXEMPT here rather than falling outside the domain). Demand beats exemption where both relations carry the parent (a @table type shaped like a connection classifies its fields, so the demand reading wins, matching the walk); within each side the rule is the first arm in the vocabularies' declared order, so the more specific reading names the row (machinery beats the directiveless catch-all). A domain coordinate with neither reading has no row: by construction the nesting-target arm complements the demand arms over plain objects, so absence marks the shadow residue (reflection-bound parents), and the agreement’s coverage gate counts resolved rows against domain coordinates to keep that construction honest. The future demand gate is this view’s DEMANDED rows anti-joined against the resolved claim view; nothing gates on it in shadow.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the domain

type_name (CHARACTER VARYING, nullable)

the coordinate’s owning type

field_name (CHARACTER VARYING, nullable)

the coordinate’s field name

verdict (CHARACTER VARYING, nullable)

DEMANDED when any demand rule covers the parent, else EXEMPT; a closed two-value vocabulary

rule (CHARACTER VARYING, nullable)

the winning rule or reason literal, drawn from the rule views' closed vocabularies in their declared precedence order

intent_resolved_node_key_column (view)

The ordered key columns a graph’s type encodes a node id from: what a @nodeId(typeName:) decode projects values into, and what an editor offers as completions after a node id opens. A reduction over the three populations that can answer, in first-tier-wins precedence, which is the resolution BuildContext.resolveTargetKeys makes with a live catalog in hand; naming it as a relation is what lets a second reader take the same answer instead of re-deriving it, the editor being that reader and the reason the view earns its place independently of any one consumer. The tiers carry ordered lists rather than independent facts per position, so the pick is by type and never by the (type, position) coordinate: one tier wins for a type and its whole list is taken. Splicing one tier’s column into another tier’s order is the transposition the resolution’s own reasoning warns about, an @node(keyColumns:) pinning an order the metadata does not share projecting columns against the order the decode returns values in, and a per-position pick is exactly how it would arrive. The pick is therefore DENSE_RANK over the tiers rather than intent_field_column_table’s ROW_NUMBER, which is the same window mechanism reading a tier rather than a row: ROW_NUMBER partitioned by the type would keep position zero and discard the rest of the winning list. An ambiguous binding resolves no key columns on the lower two tiers both. Each reaches a table through intent_resolved_type_binding, which carries candidates and declines to pick between a @table and a routine return that name different tables, and two candidate tables are two different key tuples: picking one would encode ids against a table the author never named. Only the pinned-SDL tier survives it, graphitron_node_key_column being keyed by graph and type and needing no table to answer. A type whose binding is ambiguous and whose keyColumns are unpinned therefore has no row, and naming that ambiguity is the detection stratum’s job rather than this relation’s. Absence means no tier answered, which is what the resolution reports as an error rather than a default. Whether a resolved name is a column the table actually has is deliberately not asked here: the pinned tier answers without a table at all, so a name that resolves against nothing is a row here and a detection elsewhere, on intent_node_metadata_defect’s terms for the tier it reads. The JOOQ_METADATA tier’s sibling spelling is intent_inferred_node_type, which asks the same well-formed-stated-metadata question on a different stand, the @table binding alone rather than this reduction, for the reason that view’s comment gives; the two carry the conjunction twice and name each other so a reader who finds one finds the pair, and extracting it into a relation on sql_table’s own key is the follow-on neither performs unilaterally.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from whichever tier answered

type_name (CHARACTER VARYING, nullable)

the graph type whose node key this row is one column of

position (INTEGER, nullable)

0-based position within the key, dense from zero, in the order the winning tier states; the order the encoded identity depends on, which is why the pick keeps a tier’s list whole

column_name (CHARACTER VARYING, nullable)

the key column’s name as the winning tier spells it: as written on the pinned tier, as the generated class stated it on the metadata tier, and the catalog’s own name on the primary-key tier. Matching against a table’s columns is case-insensitive wherever a reader does it, which is settled convention rather than this relation’s rule. No fold is exposed beside it, and the reason is not that the tiers are three: intent_spelled_table is a union across as many arms with no single owning relation either, and it reads each arm’s stored fold internally without trouble. What it does not do is expose one, because no view in this schema does; forwarding a fold through a derived view is what the folded columns' own comments forbid, a fold being minted on the base relation a comparison joins. What this relation hands out is a spelling rather than a resolved column, which is what makes the question of whether handing out a spelling is the right payload here a live one rather than a closed door, and it is asked on the roadmap rather than settled by this comment. A reader matching an authored spelling against this column therefore folds this side at the crossing and joins the authored side’s own generated column, which is where the schema mints one

tier (CHARACTER VARYING, nullable)

which population answered, in a closed vocabulary of three: SDL_PINNED from an @node(keyColumns:) list, JOOQ_METADATA from the well-formed node metadata the bound table’s generated class states, CATALOG_PRIMARY_KEY from the bound table’s primary key under a node type, read off intent_node_type rather than the authored @node arm alone because that view is the one relation a reader of nodehood joins. Widening it there is inert today and stated as such rather than as a fix: the inferred arm requires well-formed node metadata, well-formedness requires a declared key-columns list, and that list is what the JOOQ_METADATA tier above answers with, so an inferred node type always resolves on the higher tier and this one only ever fires under an authored @node. It is the union anyway, so the tier stops being wrong rather than starting to be right if inference ever loosens. The order is the resolution’s own precedence, and the column is what lets a test pin which tier fired rather than only that the columns came out right

intent_resolved_node_key_projection (view)

An argMapping binding that decodes a node id and projects one column out of the decoded key, where the projected value can actually reach the parameter it is bound to: the candidate rows beside it, joined to the consuming parameter’s own Java type and kept only where the two agree. The reduction the whole item turns on, and the row an emitter reads to know which column of a decoded record to hand a routine parameter. A reduction over the relations beside it rather than a derivation of its own, which is what the resolved_ prefix names: the path resolution is intent_argmapping_segment_binding’s, reduced to a leaf next door, the key list is intent_resolved_node_key_column’s, the name match and the column’s type are intent_argmapping_key_column_candidate’s, and the parameter’s type is intent_argmapping_bound_parameter_type’s; this is only where they meet. The type agreement is a join predicate and not a check performed after the fact, which is the whole of why it is sound: an emitter reads this relation, so a pair whose types disagree is not a projection an emitter can see, and there is no order of operations in which one is emitted and then rejected. Equality of the erased Java type, no widening admitted: a SMALLINT key column bound to an Integer parameter is a disagreement here, and whether that is a mismatch worth telling an author about is a question the detection’s message answers rather than one this predicate softens, softening it being what would let a narrowing through. The gate fires only where both operands are known, and standing aside on either absence is the deliberate half. A parameter whose name the classpath census cannot report (a consumer compiled without -parameters, a primitive int, a reference resolving no method) and a column the catalog cannot type (a node type with no unambiguous table binding, a pinned key column the bound table does not have) both leave the pair projecting exactly as it did before this predicate existed. Requiring the match in either case would have turned such a pair into one that is neither a projection nor a defect, which is the silence this whole family exists to close, and on the column side it would additionally have contradicted the key-column relation’s own rule that a pinned name resolves without a table. Standing aside leaves those where they were, projections whose types nothing checked, with the compiler’s own error as the backstop it always was. So the gate strictly adds rejections and removes no emission, which is what makes it safe to land as a join rather than as a staged flip. One trailing segment or none, never two and never a minimum, and where there is one it is reached by position: all of that is the candidate relation’s, stated there. The none case is the inferred form, a one-column key needing no segment to name it, and it resolves here on exactly the terms the authored form does: the same column, the same type reached the same way, the same row shape. So this relation is read without asking which of them a row came from, which is what makes the two one emission rather than two, and a reader wanting to know reads the candidate’s trailing_segment_name. Absence means this pair is not a projection, and every way of arriving at that absence is a query over the relations beside it rather than a fact this one withheld: a leaf with nothing trailing under a key of two or more columns is the bare form a rejection closes, a leaf with two or more trailing segments is the typo, a trailing segment matching no key column is the unknown column, a candidate whose types disagree is the type mismatch, a leaf carrying @nodeId with no typeName: is the missing type name, and a pair with no leaf row at all is a path the walk rejects before the store is written. None of them is this relation’s to report, which is what keeps it a positive population an emitter can trust rather than a verdict it has to interpret.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from both sides of the reduction, which agree on it by the join

site (CHARACTER VARYING, nullable)

which SDL site spelled the pair, in intent_argmapping_pair’s closed vocabulary of eight; the column a consumer reads to know whether an emitter is wired for this projection yet

use_site (CHARACTER VARYING, nullable)

the consuming coordinate, serialized as intent_argmapping_pair serializes it; with site and position the grain, and the key a planner joins the pair relation on to recover the application ordinal a command row needs

type_name (CHARACTER VARYING, nullable)

the spelling site’s owning type

field_name (CHARACTER VARYING, nullable)

the spelling site’s field name within that type

position (INTEGER, nullable)

the pair’s 0-based position within its own argMapping list; two parameters bound from one node id are two rows at two positions, which is what lets a composite key fill both

argument_path (CHARACTER VARYING, nullable)

the path as written, carried so a message quotes the author’s own spelling rather than the resolution’s

bound_kind (CHARACTER VARYING, nullable)

ARGUMENT where the decoded node id is a field argument, INPUT_FIELD where it is an input field reached below one; carried from the binding resolution, and what tells an emitter which slot the wire value is read out of

bound_type_name (CHARACTER VARYING, nullable)

the leaf’s owning type, carried from the binding resolution

bound_field_name (CHARACTER VARYING, nullable)

the leaf’s owning field on an ARGUMENT leaf, the input field itself on an INPUT_FIELD leaf

bound_argument_name (CHARACTER VARYING, nullable)

the argument’s name on an ARGUMENT leaf; NULL on an INPUT_FIELD leaf, whose key needs no argument component

node_type_name (CHARACTER VARYING, nullable)

the node type the leaf’s @nodeId names, as written; what the wire id decodes against, and the type whose key list the column below belongs to

column_name (CHARACTER VARYING, nullable)

the projected key column, spelled as the winning key-column tier spells it rather than as the author wrote it: the decode returns values against that tier’s list, so this is the spelling that lines up with it. The author’s own spelling is in the path, one segment join away

key_position (INTEGER, nullable)

the projected column’s 0-based position within the node key. Not what an emitter reads (it names the column) but what a reader checking a composite projection asks, and what shows two parameters bound from one id take two different positions of one key

tier (CHARACTER VARYING, nullable)

which key-column population answered for this node type, carried from intent_resolved_node_key_column’s closed vocabulary of three; a diagnostic explaining why a column is or is not available reads it rather than re-deriving the precedence

column_java_type (CHARACTER VARYING, nullable)

the projected column’s Java type as jOOQ binds it, fully qualified; carried from the candidate relation. Equal to the column beside it by the join, and both are kept because a reader of one row should not have to know which side of an equality it is looking at

param_java_type (CHARACTER VARYING, nullable)

the consuming parameter’s Java type, fully qualified, from intent_argmapping_bound_parameter_type; equal to the column beside it wherever it is non-NULL, that equality being the gate this relation adds over its candidate. NULL where the parameter’s type does not resolve, which is a projection the gate stood aside for rather than one it approved; the view comment says why standing aside is the right reading and what the remaining backstop is

leaf_is_list (BOOLEAN, nullable)

whether the decoded node id is list-shaped, carried from the candidate. TRUE is a projection naming the list of this column across the decoded ids: a coherent request, so it resolves here rather than being withheld, and the consumer defers on it because no emitter builds that shape yet. A reader emitting from this relation must therefore consult it, which is why it is carried rather than filtered: filtering would have made an unbuilt shape indistinguishable from a spelling nobody asked for

intent_resolved_node_key_shape (view)

A node type’s key reduced to what a slot receiving it has to agree with: how many columns the key has, the row type that carries the whole tuple, and where the key is one column that column’s name and the Java type it binds as. The relation a destination or a refusal reads when the question is not which columns the key is but whether a given slot can hold it. Every value here is a function of the key-column relation beside it and the type’s own table binding, so this states no new fact and exists for one reason: three consumers would otherwise each aggregate the key list and each re-resolve the binding, which is the inline multiplicity the fact model’s own measurements warn about, and a reader that wants the columns themselves still reads the relation this reduces. Arity is a count over the winning tier’s whole list, which is sound only because that relation picks a tier rather than a position; a per-position pick would make this number the count of a spliced list. It is counted before the two catalog reaches below it rather than after, which is not a stylistic ordering: either outer join can in principle match a key column twice, two catalog columns folding to one name being the case, and a count taken after that would report a key longer than the key is. The record class is the generated row type of the type’s own table, absent where the binding is ambiguous, where no table binds at all, and where the catalog answers org.jooq.Record, which sql_table’s own comment says is the catalog reporting no generated record rather than a record named that; the exclusion is a join predicate here so that absence is one thing at every reader instead of two. The two sole_ columns are stated only at arity one and are NULL above it, which is determined by the arity beside them rather than by anything unknown: a composite key has no single column, so a NULL here at arity two is the key’s shape and not a missing reading. Their absence at arity one is the ordinary catalog absence: a pinned key column resolves with no table at all, on the key-column relation’s own rule, so a name that names nothing the table has still has a row there and reaches no type here. A reader gating on type agreement therefore stands aside on the NULL rather than refusing, which is the discipline intent_resolved_node_key_projection already states for its own version of this operand.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the key-column relation

type_name (CHARACTER VARYING, nullable)

the graph type whose node key this row describes; one row per type that resolved any key column at all, and no row for a type that resolved none

arity (INTEGER, nullable)

how many columns the winning tier’s key list has, one or more. The number a refusal at a single-valued slot quotes, and the number that decides whether such a slot can carry the decode at all

record_class (CHARACTER VARYING, nullable)

the fully qualified name of the generated jOOQ record for the type’s own table, which is the row type that can hold the whole key tuple whatever its arity. NULL where the type’s table binding is ambiguous or absent, and NULL where jOOQ generated no record class for the bound table. Spelled as jvm_ spells a class name, so a parameter’s declared type compares to it exactly; the classpath census never scanned the generated package, so a name here is no promise that jvm_class holds the class, on intent_type_backing.class_name’s terms

sole_column_name (CHARACTER VARYING, nullable)

at arity one, that column’s name as the winning tier spells it, carried so a message about a single-valued slot need not re-join the key list; NULL at any higher arity, where there is no single column to name

sole_column_java_type (CHARACTER VARYING, nullable)

at arity one, the Java type jOOQ binds that column as, from sql_column.binding_type: the value a single-valued slot would receive, and the left operand of the agreement such a slot requires. NULL at any higher arity by the shape of the key, and NULL at arity one where the catalog cannot answer, which is an ambiguous or absent table binding or a pinned column name the bound table does not have. A reader cannot tell those two apart from this column alone and does not need to: it reads the arity beside it first, and above one the agreement is not the question

intent_resolved_node_type_id (view)

The wire type id a graph’s node type encodes its ids under: the prefix a node id carries and a decode matches against. A first-tier-wins reduction over the three populations that can answer, in the precedence TypeBuilder applies with a live catalog in hand, and naming it as a relation is what lets a store-sourced reader take the same answer rather than re-deriving it. The sibling of intent_resolved_node_key_column, which resolves the other half of a node’s identity over its own three tiers; the two are read together wherever a decode is emitted, and they are separate relations because their tiers are different populations and neither precedence implies the other. The order is the author’s contract first: @node(typeId:) is a published wire format decoupled from whatever the jOOQ generator emits, so it wins outright wherever it is declared. Below it the generated model’s own stated type id, read through the well-formedness derivation rather than off the raw metadata relation, because a malformed constant is not an answer and the classifier rejects the type outright rather than falling through. Below that the type’s own name, which is the documented default and the reason this relation is total over node types: every node type resolves a type id, so absence here means the type is not a node rather than that its identity is unknown. Total by construction is the property a consumer relies on, and it is why the lowest tier is an unconditional arm over intent_node_type rather than a COALESCE at each reader. DENSE_RANK over the tiers rather than ROW_NUMBER, matching the key-column sibling: the pick is by type and a tier answers with one value, so the two window functions agree here, and the shared spelling is what keeps the pair readable as one precedence idiom. An ambiguous table binding costs only the metadata tier, that arm being the one that needs a table; the SDL tier answers without one and the type-name tier needs nothing at all.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from whichever tier answered

type_name (CHARACTER VARYING, nullable)

the node type whose wire identity this row states

type_id (CHARACTER VARYING, nullable)

the type id as the winning tier states it: the authored string on the SDL tier, the generated class’s stated constant on the metadata tier, and the type’s own name on the last. Compared verbatim by a decode, so no fold is exposed beside it and none is wanted: a wire format is case-sensitive

origin (CHARACTER VARYING, nullable)

which population answered, in a closed vocabulary of three: SDL_DECLARED from @node(typeId:), JOOQ_METADATA from the bound table’s well-formed node metadata, TYPE_NAME from the documented default. What lets a test pin which tier fired rather than only that the id came out right, and what a diagnostic reads to tell an author where the id they are looking at came from

intent_resolved_type_binding

Which catalog table stands for a graph’s type, from either population that can answer: the author’s @table binding and the return binding a @routine chain derives. One relation for the question every reader of a binding actually asks, which is what table, not which rule found it. A reduction over sibling views rather than a base derivation, which is the shape the resolved_ prefix names and the one intent_bound_table’s own comment reserves it for: each population is derived by its own rule from its own facts and neither is a special case of the other, so they stay separate relations and this is where they meet, as intent_type_backing is where the two populations answering for a class meet. How a binding was reached is deliberately not a column, on intent_type_backing_class’s terms: a type its @table and its routine return agree on is one binding, and a provenance column would key the relation by rule and hand every reader two rows where one table stands for the type, which is exactly the multiplication that would break the one-row-per-site property intent_field_column_scope stands on. A reader that wants the rule reads the arm, both arms being residents in their own right. Ambiguity is rows and there is no precedence: a type whose @table names one table and whose routine return lands on another is two rows, candidates says two, and which of them to believe is not this relation’s to decide. The arity is recounted over the union rather than carried from an arm, since a type the two arms answer differently is ambiguous here while each arm calls itself certain; on a type only @table binds, the recount equals the spelling arity that arm carries, so the population that had a binding before sees no change. Five readers take the resolution rather than the directive, each because its question is what table and not what was written: the position-0 seed of intent_field_reference_step_target, which is what lets a path depart a routine-result type whose @table the derivation makes redundant; both intent_field_column_scope rules that read a binding, which is what lets such a type’s own columns and its children’s resolve; intent_field_reference_discovery’s departing endpoint, whose arriving one already comes through that navigation; and intent_type_backing’s table arm, a routine result’s generated record standing for the type exactly as a stored table’s does. Two readers deliberately keep reading intent_bound_table, and both are stated rather than left to be noticed. intent_field_separate_fetch asks what makes a parent a table row rather than a producer-handed object, and whether a routine-return binding answers that is the record-handed precedence question its own comment records, not a substitution to make in passing. The editor’s declaration facts answer where a type is declared, which is a written site and not a resolution. Materialized: this relation is a table refilled from intent_resolved_type_binding_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from whichever arm produced the row

type_name (CHARACTER VARYING, not null)

the type the table stands for

table_source_name (CHARACTER VARYING, not null)

the resolved table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, not null)

the resolved table’s SQL schema; what tells two candidates of one name apart

table_name (CHARACTER VARYING, not null)

the resolved table’s SQL name. With the two columns above this is sql_table’s full key; the table’s other facts are one join away, per the referenced-side discipline sql_referential_constraint states

candidates (INTEGER, not null)

how many distinct tables stand for this type across both arms, this row’s table being one of them; 1 on an unambiguous binding, which is the guard a reader that must pick one applies. Recounted here rather than carried from an arm, for the reason the view comment gives

intent_resolved_type_binding_live (view)

This states the rule and is evaluated on demand. The canonical name intent_resolved_type_binding beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_resolved_type_binding.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_resolved_type_binding.graph_name, whose comment carries what the value means

type_name (CHARACTER VARYING, nullable)

the type_name of a row of this rule, materialized into intent_resolved_type_binding.type_name, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_resolved_type_binding.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_resolved_type_binding.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_resolved_type_binding.table_name, whose comment carries what the value means

candidates (INTEGER, nullable)

the candidates of a row of this rule, materialized into intent_resolved_type_binding.candidates, whose comment carries what the value means

intent_resolved_type_demand (view)

The type-grain demand reduction over the classification domain, mirroring the field-grain reduction: demand beats exemption, first declared arm wins within a side, and a domain member with neither reading has no row, which marks the type grain’s shadow residue (directiveless objects whose registration is decided by the embedding walk and the reflection fixed point). The shadow agreement splits that absent population into its named parts rather than treating it as one structural bucket.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the domain

type_name (CHARACTER VARYING, nullable)

the domain member the verdict is about

verdict (CHARACTER VARYING, nullable)

DEMANDED when any type demand rule covers the member, else EXEMPT; a closed two-value vocabulary

rule (CHARACTER VARYING, nullable)

the winning rule or reason literal, drawn from the rule views' closed vocabularies in their declared precedence order

intent_routine_return_binding (view)

Which catalog table a type is bound to by being what a @routine chain field returns: intent_field_chain_terminus keyed by the returned type rather than by the field. This is the binding a @routine author writes @table for today, derived instead, so the routine name is written once and the two spellings can no longer disagree. The type read is intent_field_navigated_type’s, so a connection-returning routine field binds its element type and not the wrapper, whether the generator synthesised that connection or the author declared it; that navigation is stated once in that relation and read here rather than spelled again. OBJECT only, a landing being a row and a row standing for an object type. The population is the chain read seats, and one seat is excluded: the payload carrier, a mutation root’s @routine field carrying no @reference, whose chain rows are not what the field returns but what its data field re-reads post-commit, so a binding there would name a table for a type no table stands for. The exclusion names that seat rather than the carrier because the store holds no carrier fact yet; the seat is the classifier’s own fork, which reaches the carrier resolution exactly when the parent is the mutation root and the chain has a single node, and it narrows to the carrier itself the day a carrier relation lands. That day has come and the narrowing is deliberately not taken here: intent_mutation_routine_seat states the same fork as its seat column, so the exclusion could read seat = CARRIER and mean exactly what it means today, but narrowing to the carrier itself means excluding only the seats that hold, which hands a binding to every mutation-root @routine this relation currently keeps out and changes the arity every reader of the reduction sees. That is a change to make on its own evidence, not in passing. The seat exclusion costs the routine write chain nothing, that shape carrying @reference by construction. Keyed on the root operation binding and not on the literal name Mutation, the same intended-rule form the demand rules and intent_field_separate_fetch’s root arm state. Ambiguity is rows, never a decline, on intent_bound_table’s terms: two fields returning one type off different routines are two rows and candidates says so. Nothing here is masked by an author’s @table, a type carrying both being a fact about the schema and not a conflict for this relation to settle; where the two populations meet is intent_resolved_type_binding.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the chain terminus

type_name (CHARACTER VARYING, nullable)

the type this row binds: the named type of the expression the returning field was written with, its list and non-null wrappers stripped

table_source_name (CHARACTER VARYING, nullable)

the landing table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the landing table’s SQL schema; what tells two candidates of one name apart

table_name (CHARACTER VARYING, nullable)

the landing table’s SQL name. With the two columns above this is sql_table’s full key, so the table’s kind, its columns and its generated record are each one join away

candidates (INTEGER, nullable)

how many distinct tables this type’s routine-returning fields land on, this row’s table being one of them; 1 on an unambiguous binding. Counted over this relation’s own rows rather than carried from the terminus, because a type two fields return is ambiguous here even where each field’s own chain lands certainly; stated as a column rather than left to each reader’s own count, on intent_bound_table.candidates' terms

intent_spelled_table

How a written table name resolves against the catalog census: one row per candidate table, keyed on the spelling itself rather than on any one site that wrote it. A spelling arrives already split, capture having written the two halves of it beside the value, so this view reads a partition rather than performing one: a qualified spelling binds both halves and an unqualified one, whose namespace half is null, matches on its name half alone. Both sides of both comparisons are stored folded columns, which is what makes the match an equality an index can serve instead of a fold computed per candidate row. The catalog side scopes through store_graph_source so a sibling graph’s tables never resolve here. Keyed on the spelling because the rule does not vary by site: @table(name:), a @reference path element’s table, its argument-site and @referenceFor siblings, @mutation’s delete target and @routine(name:) all name a table the same way, and a resolution with several askers is a relation rather than a subquery repeated in each of them. The routine name is in that list because jOOQ models a table-valued function’s result as a catalog table like any other, so the name an author writes in @routine(name:) is a table spelling and resolves under this rule with nothing routine-specific about it; what makes the resolved row a function rather than a stored table is sql_table.table_type, which a reader that means the function form filters on and this view does not, its job being the spelling and not the kind. The population is therefore every spelling this graph authors anywhere, including graphitron_table’s type-name fallback, which is a spelling by the time resolution sees it. Ambiguity is rows, never a decline: a name two schemas both declare is two rows and candidates says so, leaving the reading to the reader. Materialized: this relation is a table refilled from intent_spelled_table_live on the capture cadence, per graph, under the registration in meta_materialize, which carries why. The rule above is stated once, in that view; these rows are what it computed for each captured graph.

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, carried from the authoring relation

spelling (CHARACTER VARYING, nullable)

the table name as written at some site in this graph, qualifier included where one was written; the key this resolution answers for

table_source_name (CHARACTER VARYING, nullable)

the resolved table’s catalog partition, the first column of the sql_table key this row names

table_schema (CHARACTER VARYING, nullable)

the resolved table’s SQL schema; what tells two candidates of one spelling apart

table_name (CHARACTER VARYING, nullable)

the resolved table’s SQL name. With the two columns above this is sql_table’s full key

candidates (INTEGER, nullable)

how many tables the spelling resolves to, this row being one of them; 1 on an unambiguous spelling

intent_spelled_table_live (view)

This states the rule and is evaluated on demand. The canonical name intent_spelled_table beside it is the table this view is materialized into on the capture cadence, which is what every reader spells and what the registration in meta_materialize records; a reader naming this relation instead is asking for on-demand evaluation and will get it. The rule itself, and what each column means, is documented on intent_spelled_table.

Columns
graph_name (CHARACTER VARYING, nullable)

the graph_name of a row of this rule, materialized into intent_spelled_table.graph_name, whose comment carries what the value means

spelling (CHARACTER VARYING, nullable)

the spelling of a row of this rule, materialized into intent_spelled_table.spelling, whose comment carries what the value means

table_source_name (CHARACTER VARYING, nullable)

the table_source_name of a row of this rule, materialized into intent_spelled_table.table_source_name, whose comment carries what the value means

table_schema (CHARACTER VARYING, nullable)

the table_schema of a row of this rule, materialized into intent_spelled_table.table_schema, whose comment carries what the value means

table_name (CHARACTER VARYING, nullable)

the table_name of a row of this rule, materialized into intent_spelled_table.table_name, whose comment carries what the value means

candidates (INTEGER, nullable)

the candidates of a row of this rule, materialized into intent_spelled_table.candidates, whose comment carries what the value means

intent_synthesized_federation_key (view)

Federation’s node-entity rule as a relation: which node types get a @key(fields: "id") nobody wrote, because federation needs the entity declaration visible in the emitted SDL and a node carries a globally-unique id by definition. A derivation and not a capture: the rule reads the SDL claim rows and the node metadata a generated class publishes, so its inputs span two corpora and its output is computable from captured facts, which is what puts it in this stratum rather than in the walk that used to run it. The three conditions are the live rule’s. The graph is federation-linked, which is a predicate over graphitron_link.url as graphitron_link’s own comment says, and the decode rather than the verbatim twin: reading the argument value out of graphql_schema_directive_arg would mean compensating for AST quoting, which is exactly the string surgery a decoded relation exists to retire. A url the author omitted is a null and matches nothing, which is the live predicate’s null guard falling out of the join. The type is a node, by intent_node_type. And no authored key already states the id contract, meaning no @key application on the type whose decode is exactly the single path id: one field row, one segment, and that segment named id. Positions are dense from zero in both children, so the two counts pin the shape without naming a position. That transcribes the live rule including its deliberate asymmetry, a malformed fields: argument decoding to no field rows and therefore not counting as the id key, so the misuse reaches its detection instead of suppressing synthesis on the strength of a parse failure; compound and other-field keys likewise do not count, being additional alternatives rather than the id contract. The rule’s constants appear here, in SQL, rather than in a comment each composing reader re-mints from: fields_sdl is the field-set literal the rule would have written and resolvable is true. The federation-spec prefix is a third spelling beside the two Java readers that share the constant, and is pinned to it by a named test rather than by a shared literal, a view being unable to bind a query parameter. This relation is its own provenance, which is what lets the synthesized application leave the transcription families entirely: nothing marks a synthesized row in graphql_type_directive because no synthesized row lands there.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from the membership relation

type_name (CHARACTER VARYING, nullable)

the node type the key is synthesized for; keyed with the graph, one row per type that gets one

fields_sdl (CHARACTER VARYING, nullable)

the field-set literal the rule states, always id; a column and not an implied constant, so a reader composing this arm with the authored one projects the same shape from both

resolvable (BOOLEAN, nullable)

the resolvable: the rule states, always true; the synthesized entity is resolvable by construction, an opt-out being something only an author can write

intent_table_key_candidate (view)

The keys a consumer may identify a row of a table by, in the order the generator considers them. One row per surviving candidate, ranked, and the rank is the whole point: a write surface handed a set of columns takes the first candidate those columns cover, so a relation that listed the candidates unordered would leave the choice to whoever read it and two readers could disagree. The order is the generated model’s own, the primary key first and the remaining unique keys in the enumeration jOOQ hands out, which is why sql_constraint.key_position is captured rather than derived. Two projections come with that order and both are the generator’s rather than this relation’s. A unique key whose column set an earlier candidate already carries is dropped, so a table whose primary key is also declared unique offers one candidate and not two, and the survivor is the earlier one, which is the primary key whenever the primary key is in the tie. And a unique key resolving no columns at all is dropped, where a primary key in that state is kept: an empty primary key is a fact about a table nothing can identify a row of, and a consumer meets it as a candidate that covers nothing rather than as a table with no candidates. That the columns resolve at all is a property of capture here rather than a case to handle: sql_constraint_column carries a foreign key into sql_column, so a key naming a column the catalog does not have could not have been written. Absence is a table declaring no uniqueness constraint, which is every view and every table nothing identifies a row of, and it is what a write surface needing an identity meets when it finds nothing to cover. The columns themselves are not here. They are sql_constraint_column’s, in its own position order, joined on the constraint name this relation gives; putting them here would make the grain a column and the rank would have to be repeated down every row of a key.

Columns
source_name (CHARACTER VARYING, nullable)

the owning catalog partition’s generated-package source, carried from sql_constraint

table_schema (CHARACTER VARYING, nullable)

the table’s SQL schema

table_name (CHARACTER VARYING, nullable)

the table’s SQL name; with the two columns above, sql_table’s key

constraint_name (CHARACTER VARYING, nullable)

the surviving candidate’s constraint name, sql_constraint’s key within the table and what a reader joins sql_constraint_column on to get the key’s columns in position order

primary_key (BOOLEAN, nullable)

whether this candidate is the table’s primary key. Not the rank: a table may declare a primary key and unique keys alike, and the rank already says which comes first, so this says which kind of identity a consumer ended up with when it reports one

candidate_rank (INTEGER, nullable)

where this candidate sits among the survivors, counting from zero, in the order a consumer considers them: the primary key first where there is one, then the unique keys in the generated model’s enumeration. A consumer taking the first candidate its columns cover reads this ascending and stops

intent_type_backing (view)

What class stands for a graph’s type, from either population that can answer: the type’s table binding read through the table’s generated record, and the closure over producer returns and accessor hops. The table arm reads intent_resolved_type_binding and not the @table population alone, because what puts a generated record behind a type is that some table stands for it, and a routine chain’s return binding stands for one exactly as a written @table does; a reader wanting only the written population joins the arm. One relation for the question every consumer of a backing actually asks, which is what class, not which walk found it. A view coalescing two relations rather than a base with a provenance tag, on the stratum’s provenance rule: each population is derived by its own rule from its own facts and neither is a special case of the other, so they are separate relations and this is where they meet. Both arms carry the same payload, one binary class name, and they can do that only because sql_table records the record class; before that fact was captured the arms had nothing in common and this view could not be stated without four columns NULL by kind. A table whose generated model has no record class reports org.jooq.Record, and that is not a backing, so the arm drops it and the type is unbacked here, the same silence a type no producer reaches already gets. Ambiguity is rows on both arms and nothing is preferred: a type its @table binding and its closure answer differently is two rows, and intent_type_backing_conflict over this view is where a reader learns so. The walk resolves that pair by precedence, reading the table and never looking at the class, which is a reading a consumer may still apply by filtering on declared_via; what it may not do here is mistake the precedence for agreement.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from whichever arm produced the row

type_name (CHARACTER VARYING, nullable)

the SDL type the class stands for

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the backing class, spelled as the jvm_ census spells a class name on both arms. On the table arm this is the generated jOOQ record, which the census deliberately never scanned, so a class name here is not a promise that jvm_class holds the class

declared_via (CHARACTER VARYING, nullable)

which population answered, a closed two-value domain: BOUND_TABLE for the resolved table binding read through its table’s record class, whichever rule bound it, BACKING_CLOSURE for the reachability over producer returns and accessor hops. Provenance, never a preference; a reader that wants one arm filters on it and owns having chosen

intent_type_backing_class

A graph’s type is backed by a class: the reachability of intent_field_accessor_hop’s edges from the classes the graph’s producer methods deliver. The seeds are intent_type_backing_seed, which states both axes and says which of this relation’s rows a producer grounded rather than a hop reached; the closure then reads each backed type’s fields off its class and backs what they return with what the member delivers. Objects and input objects only, on both ends. A class stands for a composite type by answering its fields, and an interface’s implementors and a union’s members are not what a hop lands on, so an SDL name of any other kind is where the closure stops rather than a row it declines to write; a field typed by a scalar therefore falls away here without any reject list over Java classes, which is the population the walk this replaces excludes by naming String, Boolean, the java packages and the rest one at a time. One closure condition is applied and it is not a hop’s property: a coordinate that has a producer of its own is not read off its parent, its value coming from the method rather than from the member, so the hop over it is no edge of this closure. Materialized, not a view, for intent_type_domain’s reason exactly: the closure is over the SDL type graph, which is cyclic, and H2 has no safe recursive view form for one. Written by a capture-cadence derivation writer that clears its own graph partition and re-derives after every flush, so on any settled store these rows are current for every captured graph. Ambiguity is rows and there is no first-wins. A type two seeds answer differently is two rows and intent_type_backing_conflict names it, where the walk suppresses the second observation to protect the first and leaves the disagreement unobservable. A type a seed and a hop answer differently is two rows here as well, and there the walk’s suppression is doing more than ordering: a hop reads the parent’s member type without checking it against the child’s own grounding, so it can land on a class that is wrong rather than merely second. Which of those two rows to believe is intent_type_backing_seed’s to tell a reader, not this relation’s to decide. How a binding was reached is deliberately not a column: a class reached by two routes is one backing, so a route column would key the relation by path and multiply every reader’s rows by however many routes converged; the routes are the seed and hop relations' own rows for a reader that wants them. An arity is absent for a different reason: it is an aggregate over this relation’s own rows, so storing it beside them would put a function of the relation inside the relation, which a materialization has to earn and this one cannot. Both axes seed it, on intent_type_backing_seed’s terms: a producer’s return backs the type the field names and a producer’s parameter backs the type of the argument it is fed from, and that is one closure rather than two, an input object seeded from a parameter having its own fields read off that class by the frontier that reads an output type’s. Three populations remain absent while the derivation is built out, each queued for adjudication against the walk’s shadow rather than assumed harmless. A @table-bound type seeds nothing here: that population is intent_bound_table’s, and the classes it would seed are the generated jOOQ records the classpath census excludes by design, so the subtree below one is unreachable from the store rather than merely unwritten; intent_type_backing is where the two populations meet. The walk’s cardinality guard is not applied, so a single-object field produced by a collection return backs its type here where the walk reads a carrier and declines. And the two-level carrier fork is not applied, so a payload wrapper backs itself here where the walk reaches past it to the data field it wraps; both of those are the cardinality reading, which is its own fact and not a clause of this one.

Primary key: (graph_name, type_name, class_name). Foreign key: (graph_name) references store_graph (graph_name). Foreign key: (graph_name, type_name) references graphql_type_coordinate (graph_name, type_name).

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, not null)

the SDL type the class backs; an object or an input object, and a captured type, which is what makes the type FK structural

class_name (CHARACTER VARYING, not null)

the fully-qualified binary name of the class backing the type, spelled as the jvm_ census spells a class name so the two join without normalising. Not a foreign key, on intent_declared_type_element.element_class’s terms: a class the census never reached is the ordinary case at the end of a declared type, and what a producer delivers is a fact whether or not an entry declared it. Not unique per type either, ambiguity being rows here

intent_type_backing_conflict (view)

The types the store answers with more than one backing class: one row per type whose producers, accessor hops and @table binding do not all name the same class. Stated over the coalesced intent_type_backing rather than over one arm, because a type contested across the two populations is contested in exactly the sense a consumer needing one class cares about, and an arm-local view would have called that agreement. Two disagreements therefore land here. Two producers answering differently is the one the closure surfaces, a population nobody could previously ask about: the walk resolves it by refusing the second observation and folding the survivors, so a contradiction between producers is either invisible or arrives as a rejection with the losing side already discarded. A @table binding and a reached class answering differently is the other, which the walk resolves by precedence, reading the table without ever consulting the class; that is a defensible reading and a consumer may still apply it, but it is a choice, and a relation that folded it in would have hidden the choice rather than recorded it. Counted over distinct class names, not rows, so one class both arms name is one answer and not a contest. The arity is all this relation adds: the contesting classes themselves are rows on intent_type_backing under this relation’s own key, so a consumer wanting them joins there and gets one row per class, where a set serialized into one column here would have answered set equality and nothing else. A view over the coalesce rather than a column on the closure, on intent_authored_claim_conflict’s terms: the contested population is a grouping over rows already held, and it costs nothing to state on read. Nothing gates on these rows yet. The reading this relation is shaped for is that a contested type is a rejection at whichever consumer needs one class, and the arity is what such a rejection stands on, which is why it is here rather than left to each reader’s own count.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from intent_type_backing

type_name (CHARACTER VARYING, nullable)

the contested SDL type

candidates (INTEGER, nullable)

how many distinct classes back the type, always two or more here; distinct, so a class both arms name counts once, and the arity a rejection stands on, on intent_bound_table.candidates' terms

intent_type_backing_seed (view)

A graph’s type is backed by this class by a producer of its own, rather than by being read off some other type’s class. Two arms, one per axis, and they are the seeds intent_type_backing_class closes over: a field with an authored Java reference backs the type it returns with the class the resolved method delivers, and a producer’s parameter backs the type of the argument it is fed from with the class that parameter delivers. Which argument feeds a parameter is the parameter’s own name unless an argMapping entry redirects it, in which case it is the head of the path, read from graphitron_argument_path_segment. Objects and input objects only, as in the closure, and a parameter the consumer compiled without -parameters feeds nothing. Every row here is a row of intent_type_backing_class too, this relation being where that one starts; what it adds is which of that relation’s rows a producer grounded. Not a column on the closure, for the reason that relation gives for having no route column: a class reached both by a seed and by a hop is one backing and one row there, and a route column would multiply every reader’s rows by however many routes converged. Kept as its own relation, grounding is a join and the closure keeps its grain. Why a reader would want it: the classification walk this family shadows settles a type’s groundings before it propagates anything, and then declines to read an already-grounded type off a parent’s member, because a hop reads the parent’s member type without checking it against the child’s own grounding and can therefore land on a class that is simply wrong. A reader reproducing that precedence takes a type’s rows from here when it has any and from the closure otherwise. The precedence is the reader’s and not this relation’s, which states only where a backing came from.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from intent_field_producer_method

type_name (CHARACTER VARYING, nullable)

the SDL type the producer grounds; the field’s named type on the return arm, the argument’s named type on the parameter arm

class_name (CHARACTER VARYING, nullable)

the fully-qualified binary name of the class the producer delivers at that position, once the containers come off; spelled as the jvm_ census spells a class name, on intent_type_backing_class.class_name’s terms

intent_type_demand (view)

The types that require a type-grain classification verdict. Directly type-grain (no projection involved): the root arm states the intended binding-keyed rule (today’s walk mints RootType for the three literal names, so a renamed root type is a pinned demanded-but-unregistered population, the same hole as its fields); every reachable interface and union classifies at its own visit, so those arms are kind-wide less the underscore short-circuit; connection machinery types are registered by the promotion that recognizes them, so the machinery reading appears here as demand while the same types' fields are exempt, and the arm reuses the exemption view’s recognition rather than restating it; producer payloads take a carrier or result verdict at their producing edge, reused from the field-rule arm the same way. Directiveless objects with no producer are deliberately absent from both this view and the type exemption: whether such a type ends registered (a nesting target some edge embeds) or absent (an orphan) is decided by the embedding walk and the reflection fixed point, which is the type grain’s shadow residue until those arms migrate. Leaf kinds (scalar, enum, input) are the exemption view’s named deferral rather than absent rows.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried through from every arm’s base relation

type_name (CHARACTER VARYING, nullable)

the type the rule demands a verdict for

rule (CHARACTER VARYING, nullable)

why the type is demanded; a closed vocabulary (ROOT_OPERATION, TABLE_TYPE, ERROR_TYPE, INTERFACE_TYPE, UNION_TYPE, CONNECTION_MACHINERY, PRODUCER_PAYLOAD)

intent_type_domain

The classification domain’s type members: every named type, of every kind, the generator’s intended traversal reaches from its seeds. Named for the assertion, not the graph operation, because the seeds are generator policy rather than neutral schema reachability: root operation bindings, @node carriers, types declaring implements Node, authored @key carriers, and the argument types of directive definitions that survive into the emitted schema, where survivorship is read from each definition’s own source (graphitron’s bundled directive vocabulary is build-time only) rather than from a name set held in Java, so the seeds are a function of the captured document throughout. Every seed is an SDL fact, which is what makes this a one-corpus derivation: the node arm seeds on the declaration alone, deliberately over-approximating node inference, whose other two conjuncts (a @table binding, well-formed node metadata on the bound table) decide what nodehood means and never whether the author declared it. Seeding is monotone, so the superset answers membership correctly, and a type declaring the Relay contract over no table or over defective metadata is a member that gains diagnostics instead of vanishing. Materialized, not a view: the closure over cyclic type graphs has no safe H2 view form (a recursive UNION does not terminate on cycles, and the path-guarded form enumerates simple paths), and the descent rule is graphql-java’s own child semantics rather than something SQL should restate edge kind by edge kind. Written by the SDL gatherer’s rooted traversal over the schema its assembly stage produced, inside the capture transaction, so on any settled store these rows are current for every captured graph. A run whose registry did not assemble has no schema to traverse and leaves this partition empty; that emptiness is read together with the ASSEMBLY verdict in graphql_schema_error, never alone.

Primary key: (graph_name, type_name). Foreign key: (graph_name) references store_graph (graph_name). Foreign key: (graph_name, type_name) references graphql_type_coordinate (graph_name, type_name).

Columns
graph_name (CHARACTER VARYING, not null)

the owning graph’s partition, anchored by store_graph; the leading key dimension that keeps one workspace’s graphs apart

type_name (CHARACTER VARYING, not null)

a member of the graph’s classification domain; lands only on captured types, which is what makes the type FK structural

intent_type_exemption (view)

The types whose type-grain verdict is intentionally not demanded yet. The underscore arm transcribes the walk’s name short-circuit at every kind (a federation-injected _Service or _Entity, and any author-declared underscore type, never classifies). The leaf-kind deferral arm is a bound carried as rows rather than a test-side filter: reachable scalars, enums and input objects do receive verdicts today, but their demand rules belong to those classifiers' own migration slices, so this arm retires arm-by-arm as they land and the shadow agreement reads the bound as data. Arms are unmasked; the resolved view owns precedence.

Columns
graph_name (CHARACTER VARYING, nullable)

the owning graph’s partition, carried from graphql_type

type_name (CHARACTER VARYING, nullable)

the exempted type

reason (CHARACTER VARYING, nullable)

why the type’s verdict is not demanded; a closed vocabulary (UNDERSCORE_TYPE, LEAF_KIND_DEFERRED)