From 003092cdf375694d0a07bc3f4dee2b0b514c69cb Mon Sep 17 00:00:00 2001 From: Maximiliano Osorio Date: Sun, 9 Aug 2026 16:56:58 -0400 Subject: [PATCH] fix(ui-react): show every model in the model tree, not only type sdm#Model (#98) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three queries that read modelcatalog_software filtered on type: { _eq: "https://w3id.org/okn/o/sdm#Model" }. The column classifies a model — Empirical, Coupled, Theory-Guided and so on — it does not say whether a row is a model. Every row the ETL migrated matched `?id a sdm:Model` in the RDF and stored the most specific subtype found; rows written through the REST API's generic `softwares` resource carry the ontology superclass sd#Software. So the predicate hid real models. Against TACC's catalog the thread wizard showed 18 of 175 leaf configurations and 0 of the 61 with every required input annotated. All 44 Height Above Nearest Drainage configurations were hidden, so a search for HAND returned "No models match your search." - GetModelTreeWithRegions — the thread wizard Models step - GetModelTree — /regions/:id/models - GetModelFamilies — the Model Family picker on registration, which could not offer any family whose type is a subtype of sdm#Model An allowlist of subtypes is not the fix. model-catalog-api keeps one (getSoftwareTypeFilter in service.ts) and it is already stale: it returns 44 of TACC's 55 software rows. Verified live against TACC's Hasura: all three documents now return 55 software, 51 versions, 175 leaf configurations, 44 of them HAND. graphql.ts regenerated by graphql-codegen from the committed admin-schema snapshot, not hand-edited. --- .../__tests__/model-tree-type-filter.test.ts | 52 +++++++++++++++++++ ui-react/src/graphql/generated/graphql.ts | 10 +--- ui-react/src/graphql/generated/modeling.ts | 9 ++-- .../src/graphql/queries/model-catalog.graphql | 18 ++++--- 4 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 ui-react/src/graphql/__tests__/model-tree-type-filter.test.ts diff --git a/ui-react/src/graphql/__tests__/model-tree-type-filter.test.ts b/ui-react/src/graphql/__tests__/model-tree-type-filter.test.ts new file mode 100644 index 0000000..2a75b19 --- /dev/null +++ b/ui-react/src/graphql/__tests__/model-tree-type-filter.test.ts @@ -0,0 +1,52 @@ +import { describe, it, expect } from 'vitest'; +import { print, type DocumentNode } from 'graphql'; +import { GetModelTreeDocument, GetModelFamiliesDocument } from '@/graphql/generated/graphql'; +import { GetModelTreeWithRegionsDocument } from '@/graphql/generated/modeling'; + +/** + * Regression guard for #98. + * + * `modelcatalog_software.type` classifies a model — Empirical, Coupled, + * Theory-Guided, and so on. It does not say whether a row is a model. Every row + * the ETL migrated matched `?id a sdm:Model` in the RDF, and the column holds + * the most specific subtype found; rows written through the REST API's generic + * `softwares` resource carry the ontology superclass `sd#Software`. So any + * predicate on `type` hides real, runnable models. + * + * Against TACC's catalog the old `type: { _eq: "sdm#Model" }` predicate reduced + * the model tree to 18 of 175 leaf configurations, and to 0 of the 61 that have + * every required input annotated in CKAN. + * + * An allowlist of "model" subtypes is not the fix either. `model-catalog-api` + * keeps one (`getSoftwareTypeFilter` in `service.ts`) and it is already stale — + * it returns 44 of TACC's 55 software rows, silently dropping three subtypes it + * was never taught plus every `sd#Software` row. + */ + +const DOCUMENTS: Array<[string, DocumentNode]> = [ + ['GetModelTree', GetModelTreeDocument], + ['GetModelFamilies', GetModelFamiliesDocument], + ['GetModelTreeWithRegions', GetModelTreeWithRegionsDocument], +]; + +describe('model-tree queries do not filter software by ontology type', () => { + it.each(DOCUMENTS)('%s selects modelcatalog_software', (_name, doc) => { + expect(print(doc)).toContain('modelcatalog_software'); + }); + + it.each(DOCUMENTS)('%s carries no type predicate', (_name, doc) => { + expect(print(doc)).not.toContain('type:'); + expect(print(doc)).not.toContain('w3id.org/okn/o/sdm#'); + expect(print(doc)).not.toContain('w3id.org/okn/o/sd#'); + }); + + it.each(DOCUMENTS)('%s passes modelcatalog_software no where argument', (_name, doc) => { + const rootField = doc.definitions + .flatMap((def) => (def.kind === 'OperationDefinition' ? def.selectionSet.selections : [])) + .find((sel) => sel.kind === 'Field' && sel.name.value === 'modelcatalog_software'); + + expect(rootField).toBeDefined(); + const args = rootField && rootField.kind === 'Field' ? (rootField.arguments ?? []) : []; + expect(args.map((a) => a.name.value)).toEqual(['order_by']); + }); +}); diff --git a/ui-react/src/graphql/generated/graphql.ts b/ui-react/src/graphql/generated/graphql.ts index d48f5e3..7f6f1ac 100644 --- a/ui-react/src/graphql/generated/graphql.ts +++ b/ui-react/src/graphql/generated/graphql.ts @@ -27659,10 +27659,7 @@ export type UpdateModelParameterMutationResult = Apollo.MutationResult; export const GetModelTreeDocument = gql` query GetModelTree { - modelcatalog_software( - order_by: {label: asc} - where: {type: {_eq: "https://w3id.org/okn/o/sdm#Model"}} - ) { + modelcatalog_software(order_by: {label: asc}) { id label versions(order_by: {label: asc}) { @@ -28222,10 +28219,7 @@ export type GetStandardVariablesWithUnitsSuspenseQueryHookResult = ReturnType; export const GetModelFamiliesDocument = gql` query GetModelFamilies { - modelcatalog_software( - order_by: {label: asc} - where: {type: {_eq: "https://w3id.org/okn/o/sdm#Model"}} - ) { + modelcatalog_software(order_by: {label: asc}) { id label versions(order_by: {label: asc}) { diff --git a/ui-react/src/graphql/generated/modeling.ts b/ui-react/src/graphql/generated/modeling.ts index ea6f08f..4e7e1c7 100644 --- a/ui-react/src/graphql/generated/modeling.ts +++ b/ui-react/src/graphql/generated/modeling.ts @@ -1389,12 +1389,13 @@ export function extractModelIO(config: ModelIOConfig): ModelIO { return { inputs, outputs, producesVariableIds }; } +// No type predicate — deliberate. `modelcatalog_software.type` classifies a model +// (Empirical, Coupled, Theory-Guided, ...); it does not say whether a row is a model. +// Filtering on `sdm#Model` showed the thread wizard 18 of TACC's 175 runnable leaf +// configurations, and none of the 61 that have data annotated. See #98. export const GetModelTreeWithRegionsDocument = gql` query GetModelTreeWithRegions { - modelcatalog_software( - order_by: { label: asc } - where: { type: { _eq: "https://w3id.org/okn/o/sdm#Model" } } - ) { + modelcatalog_software(order_by: { label: asc }) { id label versions(order_by: { label: asc }) { diff --git a/ui-react/src/graphql/queries/model-catalog.graphql b/ui-react/src/graphql/queries/model-catalog.graphql index 0fb02e1..8183835 100644 --- a/ui-react/src/graphql/queries/model-catalog.graphql +++ b/ui-react/src/graphql/queries/model-catalog.graphql @@ -1,11 +1,13 @@ #import "../fragments/model-catalog.graphql" #import "../fragments/region.graphql" +# No type predicate — deliberate. `modelcatalog_software.type` classifies a model +# (Empirical, Coupled, Theory-Guided, ...); it does not say whether a row is a model. +# The ETL only migrated `?id a sdm:Model` and stored the most specific subtype, and +# rows created through the REST API's generic `softwares` resource carry the +# superclass `sd#Software`. Filtering on any one value hides real models. See #98. query GetModelTree { - modelcatalog_software( - order_by: { label: asc } - where: { type: { _eq: "https://w3id.org/okn/o/sdm#Model" } } - ) { + modelcatalog_software(order_by: { label: asc }) { id label versions(order_by: { label: asc }) { @@ -163,11 +165,11 @@ query GetStandardVariablesWithUnits { } } +# No type predicate — same rule as GetModelTree above (#98). This feeds the +# "Model Family" picker on registration; filtering it made it impossible to +# register a new version under any model whose type is a subtype of sdm#Model. query GetModelFamilies { - modelcatalog_software( - order_by: { label: asc } - where: { type: { _eq: "https://w3id.org/okn/o/sdm#Model" } } - ) { + modelcatalog_software(order_by: { label: asc }) { id label versions(order_by: { label: asc }) {