Semantic review

Retrieve, assess, and apply ontology candidates without weakening curator control.

Deterministic suggestions

suggest_semantics() searches for candidates for dictionary, code, table, and dataset targets. Measurement columns use six ordered semantic roles: variable, property, entity, unit, constraint, and statistical modifier.

There is no dictionary method slot. sdp-0.3.0 removed it: a method is how a value was produced, not part of what the value is, so it moved to the three placements migrate_sdp_methods() relocates it to. The method role survives only for codes.csv term targets — a code value naming a procedure.

from metasalmonpy import infer_dictionary, suggest_semantics

dictionary = infer_dictionary(
    observations,
    dataset_id="catch-monitoring",
    table_id="observations",
)

reviewed = suggest_semantics(
    observations,
    dictionary,
    sources=["smn", "gcdfo"],
    max_per_role=3,
)

suggestions = reviewed.attrs["semantic_suggestions"]

When sources is omitted, metasalmonpy chooses role-aware defaults. An explicitly supplied source list is a strict allowlist for initial and retry retrieval. For example, sources="smn" cannot introduce QUDT candidates.

LLM review is opt-in

Context does not enable an LLM call. You must set llm_assess=True explicitly. Context file inputs must be local paths, not parsed pandas, XML, or document objects.

reviewed = suggest_semantics(
    observations,
    dictionary,
    sources=["smn"],
    llm_assess=True,
    llm_provider="openrouter",
    llm_model="openai/gpt-5.4-mini",
    llm_context_files=["data_dictionary.csv"],
)

assessments = reviewed.attrs["semantic_llm_assessments"]

Supplying llm_context_files or llm_context_text while llm_assess=False produces a warning and makes no provider request.

Bundle review

Measurement targets are reviewed as one column bundle. The request contains the original dictionary row, existing semantics, value metadata, all six candidate slots, relevant context, and the retrieval-source policy.

The adapter preserves the public per-target format:

  • semantic_suggestions remains the candidate table;
  • semantic_llm_assessments always uses the same 30-column schema;
  • positional candidate indices remain available to callers;
  • provider failures retain the deterministic shortlist; and
  • malformed individual slots fall back without discarding valid sibling slots.

Retry processing is bounded to one round. An exact retry of the original query is preserved as a retry_search decision, marked with llm_retry_query_rejection_reason="duplicate_original_query", and skipped. Near-duplicate queries remain eligible. Escalated shortlist rejections retain llm_escalated_from="reject_shortlist".

Deterministic validators

Pure validators can downgrade unsupported accept decisions to review for:

  • missing method evidence;
  • missing constraint evidence;
  • role and ontology-type incompatibility;
  • deterministically known unit/property dimensional conflicts; and
  • curated semantic redundancy.

A downgrade clears the selected candidate but preserves model confidence and rationale as provenance. Validators never retrieve, substitute, or invent terms.

Apply reviewed choices

from metasalmonpy import apply_semantic_suggestions

updated = apply_semantic_suggestions(
    reviewed,
    strategy="llm",
    roles=["variable", "property", "entity", "unit"],
    min_llm_confidence=0.8,
)

The four core roles — variable, property, entity, unit — are eligible for automatic prefill in create_sdp() whenever a compatible candidate is found. Constraint and statistical modifier are eligible too, but only on the deterministic path and only when the column’s own name, label or description carries the evidence for the qualifier or the aggregation. The retrieval offering a hit is never enough on its own: a mean_wild_spawner_count column earns both slots, a bare count column earns neither, whatever comes back from search.

Under LLM review (llm_assess=True) the two qualifier roles are excluded outright, as the roles= argument above shows. A reviewed accept is not a licence to auto-apply the roles that change what the variable is: a mean weight and a maximum weight are different variables, which is why sdp-0.3.0 moved the modifier into the dictionary in the first place.

Everything prefilled is marked REVIEW:, including the two qualifier slots. That marking is the point rather than a detail — an unmarked constraint IRI is an unreviewed assertion sitting in a slot you never asked about.

Note

This page said the opposite until 2026-08-24: that only the four core roles were eligible and constraint and statistical modifier were left for explicit review. That was a true description of this package and a false one of metasalmon, whose deterministic path had always applied them under the same evidence gates — and each side’s prose matched its own code, so no reader was positioned to catch it. Hub Q16 ruled metasalmon right (“Yeah lets go the R way”) and this package moved. See PARITY.md row 57.

For an interactive, resumable whole-variable review, use chat_decomposition(). It persists structured state and never submits a term request automatically.

Back to top