internal/infra/pg/ontology.go
internal/infra/pg · 102 lines · 3 declarations · source
Declarations
func LoadOntology
func LoadOntology(ctx context.Context, pool *pgxpool.Pool, schema Schema) (domain.Ontology, error)
LoadOntology reads a tenant's relation vocabulary.
Why it is read rather than declared in Go
`fact.predicate` references the `predicate` table, so the database is what actually closes the set. A Go list beside it would be a second definition of a closed set, and the one that drifts is always the one no constraint enforces — at which point the extractor is told a vocabulary the database will refuse, and the failure surfaces as a foreign key violation on a claim that looked fine.
Why per tenant
A tenant is a schema, so the vocabulary is a copy per tenant. That is the cost of the hard boundary, and it is also what makes a tenant-specific vocabulary possible later without changing how anything reads it.
Read once and held, not per extraction: it is forty rows that change when a migration runs.
const selectOntologySQL
const selectOntologySQL = `
SELECT predicate, semantic_type, cardinality, object_kind, description, event
FROM {schema}.predicate
ORDER BY predicate`
Ordered by name rather than by insertion, so the list a prompt is built from is the same list on every deployment. A prompt whose vocabulary arrives in a different order is a different prompt, and extraction quality cannot be compared across runs that were not asked the same question.
func LoadVocabulary
func LoadVocabulary(ctx context.Context, pool *pgxpool.Pool, schema Schema) (domain.Vocabulary, error)
LoadVocabulary reads both closed sets an extractor needs.
One call rather than two, because they are read together on the same path and a caller that loaded one and forgot the other would get an extractor whose refusals silently stop happening — which looks like the model improving.