Class: Kumi::SchemaMetadata

Inherits:
Object
  • Object
show all
Defined in:
lib/kumi/schema_metadata.rb,
lib/kumi/schema_metadata/printer.rb

Overview

The algebra of a compiled schema, as read-only data.

A Kumi schema is, formally: a set of typed, domain-constrained inputs (free variables), a set of definitions (values and traits) each given by an expression over inputs and earlier definitions, and the **dependency relation** between them. ‘SchemaMetadata` exposes exactly that — precise, named, and total — sourced from the analyzer rather than re-derived.

Returned by ‘MySchema.schema_metadata`. It is the surface every tool over Kumi builds on (form generation, simulation harnesses, fuzzers, docs) and the self-describing contract an LLM reads to reason about a schema it cannot see the source of. See #to_h for the serializable form and #to_s/Printer for the human/LLM-readable rendering.

Defined Under Namespace

Classes: Definition, InputField, Printer

Instance Method Summary collapse

Constructor Details

#initialize(state, syntax_tree) ⇒ SchemaMetadata

Returns a new instance of SchemaMetadata.



47
48
49
50
# File 'lib/kumi/schema_metadata.rb', line 47

def initialize(state, syntax_tree)
  @state = state
  @syntax_tree = syntax_tree
end

Instance Method Details

#array_outputsArray<Symbol>

Returns:

  • (Array<Symbol>)


192
# File 'lib/kumi/schema_metadata.rb', line 192

def array_outputs = vector_definitions

#axes_for(name) ⇒ Array<Symbol>

Returns:

  • (Array<Symbol>)

Raises:

  • (KeyError)


198
199
200
201
202
203
# File 'lib/kumi/schema_metadata.rb', line 198

def axes_for(name)
  d = definition(name)
  raise KeyError, "Unknown definition: #{name}" unless d

  d.axes
end

#definition(name) ⇒ Definition?

Returns:



118
119
120
# File 'lib/kumi/schema_metadata.rb', line 118

def definition(name)
  definitions[name.to_sym]
end

#definition_namesArray<Symbol>

Returns all definition names (values and traits).

Returns:

  • (Array<Symbol>)

    all definition names (values and traits)



123
124
125
# File 'lib/kumi/schema_metadata.rb', line 123

def definition_names
  definitions.keys
end

#definitionsHash{Symbol => Definition}

Every definition (value or trait) as a Definition: kind, dtype, axes, the rendered expression, the names it reads, and the names that read it.

Returns:



113
114
115
# File 'lib/kumi/schema_metadata.rb', line 113

def definitions
  @definitions ||= build_definitions
end

#evaluation_orderArray<Symbol>

Order in which definitions are evaluated (a topological sort of the dependency relation).

Returns:

  • (Array<Symbol>)


151
152
153
# File 'lib/kumi/schema_metadata.rb', line 151

def evaluation_order
  Array(@state[:evaluation_order])
end

#hintsHash{Symbol => Hash}

Per-declaration hints (the configurable-codegen seam).

Returns:

  • (Hash{Symbol => Hash})


208
209
210
# File 'lib/kumi/schema_metadata.rb', line 208

def hints
  @state[:hints] || {}
end

#imported_namesArray<Symbol>

Names imported from other schemas (inlined at compile time).

Returns:

  • (Array<Symbol>)


174
175
176
# File 'lib/kumi/schema_metadata.rb', line 174

def imported_names
  Array(@state[:imported_declarations]&.keys)
end

#input_field(path) ⇒ InputField?

Look up one input leaf by path (array of symbols or dotted string).

Returns:



87
88
89
90
# File 'lib/kumi/schema_metadata.rb', line 87

def input_field(path)
  key = path.is_a?(String) ? path.split(".").map(&:to_sym) : Array(path)
  input_fields.find { |f| f.path == key }
end

#input_fieldsArray<InputField>

Flat list of every input leaf, each an InputField: its addressable path, dtype, declared domain, the array axes it sits under, and the key path into one array element. Navigation (‘axes`, `element_path`) is taken from the analyzer’s ‘precomputed_plan_by_fqn`, not re-derived, so it is correct through arbitrary nesting and multiple arrays.

Returns:



75
76
77
78
79
80
81
82
# File 'lib/kumi/schema_metadata.rb', line 75

def input_fields
  @input_fields ||= begin
    leaves = []
    walk_input_nodes(@state[:input_metadata] || {}, [], leaves)
    plans = @state[:precomputed_plan_by_fqn] || {}
    leaves.map { |leaf| build_input_field(leaf, plans) }
  end
end

#input_namesArray<Symbol>

Returns top-level input names.

Returns:

  • (Array<Symbol>)

    top-level input names



64
65
66
# File 'lib/kumi/schema_metadata.rb', line 64

def input_names
  inputs.keys
end

#input_planHash{String => Hash}

The raw per-path input navigation plan keyed by dotted path. Authoritative source for axis/element information; most callers want #input_fields.

Returns:

  • (Hash{String => Hash})


103
104
105
# File 'lib/kumi/schema_metadata.rb', line 103

def input_plan
  @state[:precomputed_plan_by_fqn] || {}
end

#input_treeHash

Nested tree mirroring the declared structure with domains attached.

Returns:

  • (Hash)


95
96
97
# File 'lib/kumi/schema_metadata.rb', line 95

def input_tree
  (@state[:input_metadata] || {}).transform_values { |node| node_to_tree(node) }
end

#inputsHash{Symbol => Hash}

Recursive description of the declared inputs. Shape: ‘{ name => { type:, … } }`; array entries carry an `element`, object entries carry `fields`.

Returns:

  • (Hash{Symbol => Hash})


59
60
61
# File 'lib/kumi/schema_metadata.rb', line 59

def inputs
  @state[:input_form_schema] || {}
end

#output_namesArray<Symbol>

Returns:

  • (Array<Symbol>)


189
# File 'lib/kumi/schema_metadata.rb', line 189

def output_names = outputs.keys

#outputsHash{Symbol => Hash}

Backwards-compatible alias: the output declarations keyed by name with ‘{ kind:, type:, axes: }`. Prefer #definitions.

Returns:

  • (Hash{Symbol => Hash})


184
185
186
# File 'lib/kumi/schema_metadata.rb', line 184

def outputs
  @state[:output_schema] || {}
end

#read_by(name) ⇒ Array<Symbol>

Names that read this input or definition directly.

Returns:

  • (Array<Symbol>)


165
166
167
# File 'lib/kumi/schema_metadata.rb', line 165

def read_by(name)
  Array(@state.dig(:dependents, name.to_sym))
end

#reads(name) ⇒ Array<Symbol>

Names this definition reads directly (inputs and other definitions).

Returns:

  • (Array<Symbol>)


158
159
160
# File 'lib/kumi/schema_metadata.rb', line 158

def reads(name)
  definition(name)&.reads || []
end

#scalar_definitionsArray<Symbol>

Returns definitions that reduce to a scalar (no axes).

Returns:

  • (Array<Symbol>)

    definitions that reduce to a scalar (no axes)



138
139
140
# File 'lib/kumi/schema_metadata.rb', line 138

def scalar_definitions
  definitions.select { |_, d| d.axes.empty? }.keys
end

#scalar_outputsArray<Symbol>

Returns:

  • (Array<Symbol>)


195
# File 'lib/kumi/schema_metadata.rb', line 195

def scalar_outputs = scalar_definitions

#to_hHash

Total, JSON-safe snapshot of the whole algebra. Safe to hand to a frontend, persist, or give to an LLM as a tool-use contract.

Returns:

  • (Hash)


216
217
218
219
220
221
222
223
224
# File 'lib/kumi/schema_metadata.rb', line 216

def to_h
  {
    inputs: input_fields.map(&:to_h),
    definitions: definitions.values.map(&:to_h),
    evaluation_order: evaluation_order,
    imports: imported_names,
    hints: hints
  }
end

#to_sString Also known as: to_str, inspect

Human/LLM-readable rendering of the algebra.

Returns:

  • (String)


229
230
231
# File 'lib/kumi/schema_metadata.rb', line 229

def to_s
  Printer.new(self).render
end

#trait_namesArray<Symbol>

Returns names of ‘trait` definitions.

Returns:

  • (Array<Symbol>)

    names of ‘trait` definitions



133
134
135
# File 'lib/kumi/schema_metadata.rb', line 133

def trait_names
  definitions.select { |_, d| d.kind == :trait }.keys
end

#value_namesArray<Symbol>

Returns names of ‘value` definitions.

Returns:

  • (Array<Symbol>)

    names of ‘value` definitions



128
129
130
# File 'lib/kumi/schema_metadata.rb', line 128

def value_names
  definitions.select { |_, d| d.kind == :value }.keys
end

#vector_definitionsArray<Symbol>

Returns definitions that broadcast over one or more axes.

Returns:

  • (Array<Symbol>)

    definitions that broadcast over one or more axes



143
144
145
# File 'lib/kumi/schema_metadata.rb', line 143

def vector_definitions
  definitions.reject { |_, d| d.axes.empty? }.keys
end